LCOV - code coverage report
Current view: top level - gcc - compare-elim.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.9 % 340 309
Test Date: 2024-04-20 14:03:02 Functions: 88.9 % 18 16
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Post-reload compare elimination.
       2                 :             :    Copyright (C) 2010-2024 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                 :             : /* There is a set of targets whose general-purpose move or addition
      21                 :             :    instructions clobber the flags.  These targets cannot split their
      22                 :             :    CBRANCH/CSTORE etc patterns before reload is complete, lest reload
      23                 :             :    itself insert these instructions in between the flags setter and user.
      24                 :             :    Because these targets cannot split the compare from the use, they
      25                 :             :    cannot make use of the comparison elimination offered by the combine pass.
      26                 :             : 
      27                 :             :    This is a small pass intended to provide comparison elimination similar to
      28                 :             :    what was available via NOTICE_UPDATE_CC for cc0 targets.
      29                 :             : 
      30                 :             :    This pass assumes:
      31                 :             : 
      32                 :             :    (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
      33                 :             : 
      34                 :             :    (1) All comparison patterns are represented as
      35                 :             : 
      36                 :             :         [(set (reg:CC) (compare:CC (reg) (reg_or_immediate)))]
      37                 :             : 
      38                 :             :    (2) All insn patterns that modify the flags are represented as
      39                 :             : 
      40                 :             :         [(set (reg) (operation)
      41                 :             :          (clobber (reg:CC))]
      42                 :             : 
      43                 :             :    (3) If an insn of form (2) can usefully set the flags, there is
      44                 :             :        another pattern of the form
      45                 :             : 
      46                 :             :         [(set (reg:CCM) (compare:CCM (operation) (immediate)))
      47                 :             :          (set (reg) (operation)]
      48                 :             :          
      49                 :             :        The mode CCM will be chosen as if by SELECT_CC_MODE.
      50                 :             : 
      51                 :             :    Note that unlike NOTICE_UPDATE_CC, we do not handle memory operands.
      52                 :             :    This could be handled as a future enhancement.
      53                 :             : */
      54                 :             : 
      55                 :             : #include "config.h"
      56                 :             : #include "system.h"
      57                 :             : #include "coretypes.h"
      58                 :             : #include "backend.h"
      59                 :             : #include "target.h"
      60                 :             : #include "rtl.h"
      61                 :             : #include "df.h"
      62                 :             : #include "memmodel.h"
      63                 :             : #include "tm_p.h"
      64                 :             : #include "insn-config.h"
      65                 :             : #include "recog.h"
      66                 :             : #include "emit-rtl.h"
      67                 :             : #include "cfgrtl.h"
      68                 :             : #include "tree-pass.h"
      69                 :             : #include "domwalk.h"
      70                 :             : 
      71                 :             : 
      72                 :             : /* These structures describe a comparison and how it is used.  */
      73                 :             : 
      74                 :             : /* The choice of maximum 3 uses comes from wanting to eliminate the two
      75                 :             :    duplicate compares from a three-way branch on the sign of a value.
      76                 :             :    This is also sufficient to eliminate the duplicate compare against the
      77                 :             :    high-part of a double-word comparison.  */
      78                 :             : #define MAX_CMP_USE 3
      79                 :             : 
      80                 :             : struct comparison_use
      81                 :             : {
      82                 :             :   /* The instruction in which the result of the compare is used.  */
      83                 :             :   rtx_insn *insn;
      84                 :             :   /* The location of the flags register within the use.  */
      85                 :             :   rtx *loc;
      86                 :             :   /* The comparison code applied against the flags register.  */
      87                 :             :   enum rtx_code code;
      88                 :             : };
      89                 :             : 
      90                 :             : struct comparison
      91                 :             : {
      92                 :             :   /* The comparison instruction.  */
      93                 :             :   rtx_insn *insn;
      94                 :             : 
      95                 :             :   /* The insn prior to the comparison insn that clobbers the flags.  */
      96                 :             :   rtx_insn *prev_clobber;
      97                 :             : 
      98                 :             :   /* The insn prior to the comparison insn that sets in_a REG.  */
      99                 :             :   rtx_insn *in_a_setter;
     100                 :             : 
     101                 :             :   /* The two values being compared.  These will be either REGs or
     102                 :             :      constants.  */
     103                 :             :   rtx in_a, in_b;
     104                 :             : 
     105                 :             :   /* The REG_EH_REGION of the comparison.  */
     106                 :             :   rtx eh_note;
     107                 :             : 
     108                 :             :   /* Information about how this comparison is used.  */
     109                 :             :   struct comparison_use uses[MAX_CMP_USE];
     110                 :             : 
     111                 :             :   /* The original CC_MODE for this comparison.  */
     112                 :             :   machine_mode orig_mode;
     113                 :             : 
     114                 :             :   /* The number of uses identified for this comparison.  */
     115                 :             :   unsigned short n_uses;
     116                 :             : 
     117                 :             :   /* True if not all uses of this comparison have been identified.
     118                 :             :      This can happen either for overflowing the array above, or if
     119                 :             :      the flags register is used in some unusual context.  */
     120                 :             :   bool missing_uses;
     121                 :             : 
     122                 :             :   /* True if its inputs are still valid at the end of the block.  */
     123                 :             :   bool inputs_valid;
     124                 :             : 
     125                 :             :   /* Whether IN_A is wrapped in a NOT before being compared.  */
     126                 :             :   bool not_in_a;
     127                 :             : };
     128                 :             :   
     129                 :             : static vec<comparison *> all_compares;
     130                 :             : 
     131                 :             : /* Return whether X is a NOT unary expression.  */
     132                 :             : 
     133                 :             : static bool
     134                 :    10807428 : is_not (rtx x)
     135                 :             : {
     136                 :    10807428 :   return GET_CODE (x) == NOT;
     137                 :             : }
     138                 :             : 
     139                 :             : /* Strip a NOT unary expression around X, if any.  */
     140                 :             : 
     141                 :             : static rtx
     142                 :     7760835 : strip_not (rtx x)
     143                 :             : {
     144                 :           0 :   if (is_not (x))
     145                 :           0 :     return XEXP (x, 0);
     146                 :             : 
     147                 :             :   return x;
     148                 :             : }
     149                 :             : 
     150                 :             : /* Look for a "conforming" comparison, as defined above.  If valid, return
     151                 :             :    the rtx for the COMPARE itself.  */
     152                 :             : 
     153                 :             : static rtx
     154                 :    53732992 : conforming_compare (rtx_insn *insn)
     155                 :             : {
     156                 :    53732992 :   rtx set, src, dest;
     157                 :             : 
     158                 :    53732992 :   set = single_set (insn);
     159                 :    53732992 :   if (set == NULL)
     160                 :             :     return NULL;
     161                 :             : 
     162                 :    49855452 :   src = SET_SRC (set);
     163                 :    49855452 :   if (GET_CODE (src) != COMPARE)
     164                 :             :     return NULL;
     165                 :             : 
     166                 :     4165194 :   dest = SET_DEST (set);
     167                 :     4165194 :   if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
     168                 :             :     return NULL;
     169                 :             : 
     170                 :     4165194 :   if (!REG_P (strip_not (XEXP (src, 0))))
     171                 :             :     return NULL;
     172                 :             : 
     173                 :     3142338 :   if (CONSTANT_P (XEXP (src, 1)) || REG_P (XEXP (src, 1)))
     174                 :             :     return src;
     175                 :             : 
     176                 :       95745 :   if (GET_CODE (XEXP (src, 1)) == UNSPEC)
     177                 :             :     {
     178                 :           0 :       for (int i = 0; i < XVECLEN (XEXP (src, 1), 0); i++)
     179                 :           0 :         if (!REG_P (XVECEXP (XEXP (src, 1), 0, i)))
     180                 :             :           return NULL;
     181                 :             :       return src;
     182                 :             :     }
     183                 :             : 
     184                 :             :   return NULL;
     185                 :             : }
     186                 :             : 
     187                 :             : /* Look for a pattern of the "correct" form for an insn with a flags clobber
     188                 :             :    for which we may be able to eliminate a compare later.  We're not looking
     189                 :             :    to validate any inputs at this time, merely see that the basic shape is
     190                 :             :    correct.  The term "arithmetic" may be somewhat misleading...  */
     191                 :             : 
     192                 :             : static bool
     193                 :    10860467 : arithmetic_flags_clobber_p (rtx_insn *insn)
     194                 :             : {
     195                 :    10860467 :   rtx pat, x;
     196                 :             : 
     197                 :    10860467 :   if (!NONJUMP_INSN_P (insn))
     198                 :             :     return false;
     199                 :     6445826 :   pat = PATTERN (insn);
     200                 :     6445826 :   if (asm_noperands (pat) >= 0)
     201                 :             :     return false;
     202                 :             : 
     203                 :     6352062 :   if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
     204                 :             :     {
     205                 :     4974170 :       x = XVECEXP (pat, 0, 0);
     206                 :     4974170 :       if (GET_CODE (x) != SET)
     207                 :             :         return false;
     208                 :     4974163 :       x = SET_DEST (x);
     209                 :     4974163 :       if (!REG_P (x))
     210                 :             :         return false;
     211                 :             : 
     212                 :     4831819 :       x = XVECEXP (pat, 0, 1);
     213                 :     4831819 :       if (GET_CODE (x) == CLOBBER)
     214                 :             :         {
     215                 :     4655779 :           x = XEXP (x, 0);
     216                 :     4655779 :           if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
     217                 :             :             return true;
     218                 :             :         }
     219                 :             :     }
     220                 :             : 
     221                 :             :   return false;
     222                 :             : }
     223                 :             : 
     224                 :             : /* Look for uses of FLAGS in INSN.  If we find one we can analyze, record
     225                 :             :    it in CMP; otherwise indicate that we've missed a use.  */
     226                 :             : 
     227                 :             : static void
     228                 :    12871252 : find_flags_uses_in_insn (struct comparison *cmp, rtx_insn *insn)
     229                 :             : {
     230                 :    12871252 :   df_ref use;
     231                 :             : 
     232                 :             :   /* If we've already lost track of uses, don't bother collecting more.  */
     233                 :    12871252 :   if (cmp->missing_uses)
     234                 :             :     return;
     235                 :             : 
     236                 :             :   /* Find a USE of the flags register.  */
     237                 :    26996527 :   FOR_EACH_INSN_USE (use, insn)
     238                 :    14149604 :     if (DF_REF_REGNO (use) == targetm.flags_regnum)
     239                 :             :       {
     240                 :     3063859 :         rtx x, *loc;
     241                 :             : 
     242                 :             :         /* If this is an unusual use, quit.  */
     243                 :     3063859 :         if (DF_REF_TYPE (use) != DF_REF_REG_USE)
     244                 :           0 :           goto fail;
     245                 :             : 
     246                 :             :         /* If we've run out of slots to record uses, quit.  */
     247                 :     3063859 :         if (cmp->n_uses == MAX_CMP_USE)
     248                 :           3 :           goto fail;
     249                 :             : 
     250                 :             :         /* Unfortunately the location of the flags register, while present
     251                 :             :            in the reference structure, doesn't help.  We need to find the
     252                 :             :            comparison code that is outer to the actual flags use.  */
     253                 :     3063856 :         loc = DF_REF_LOC (use);
     254                 :     3063856 :         x = PATTERN (insn);
     255                 :     3063856 :         if (GET_CODE (x) == PARALLEL)
     256                 :       25492 :           x = XVECEXP (x, 0, 0);
     257                 :     3063856 :         if (GET_CODE (x) == SET)
     258                 :     3063856 :           x = SET_SRC (x);
     259                 :     3063856 :         if (GET_CODE (x) == IF_THEN_ELSE)
     260                 :     2952850 :           x = XEXP (x, 0);
     261                 :     3063856 :         if (COMPARISON_P (x)
     262                 :     3046015 :             && loc == &XEXP (x, 0)
     263                 :     3040311 :             && XEXP (x, 1) == const0_rtx)
     264                 :             :           {
     265                 :             :             /* We've found a use of the flags that we understand.  */
     266                 :     3040311 :             struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
     267                 :     3040311 :             cuse->insn = insn;
     268                 :     3040311 :             cuse->loc = loc;
     269                 :     3040311 :             cuse->code = GET_CODE (x);
     270                 :             :           }
     271                 :             :         else
     272                 :       23545 :           goto fail;
     273                 :             :       }
     274                 :             :   return;
     275                 :             : 
     276                 :       23548 :  fail:
     277                 :             :   /* We failed to recognize this use of the flags register.  */
     278                 :       23548 :   cmp->missing_uses = true;
     279                 :             : }
     280                 :             : 
     281                 :     1975368 : class find_comparison_dom_walker : public dom_walker
     282                 :             : {
     283                 :             : public:
     284                 :      987684 :   find_comparison_dom_walker (cdi_direction direction)
     285                 :     1975368 :     : dom_walker (direction) {}
     286                 :             : 
     287                 :             :   edge before_dom_children (basic_block) final override;
     288                 :             : };
     289                 :             : 
     290                 :             : /* Return true if conforming COMPARE with EH_NOTE is redundant with comparison
     291                 :             :    CMP and can thus be eliminated.  */
     292                 :             : 
     293                 :             : static bool
     294                 :      555721 : can_eliminate_compare (rtx compare, rtx eh_note, struct comparison *cmp)
     295                 :             : {
     296                 :             :   /* Take care that it's in the same EH region.  */
     297                 :      555721 :   if (cfun->can_throw_non_call_exceptions
     298                 :      555721 :       && !rtx_equal_p (eh_note, cmp->eh_note))
     299                 :             :     return false;
     300                 :             : 
     301                 :             :   /* Make sure the compare is redundant with the previous.  */
     302                 :      555721 :   if (!rtx_equal_p (strip_not (XEXP (compare, 0)), cmp->in_a)
     303                 :      555721 :       || !rtx_equal_p (XEXP (compare, 1), cmp->in_b))
     304                 :      549048 :     return false;
     305                 :             : 
     306                 :        6673 :   if (is_not (XEXP (compare, 0)) != cmp->not_in_a)
     307                 :             :     return false;
     308                 :             : 
     309                 :             :   /* New mode must be compatible with the previous compare mode.  */
     310                 :        6673 :   machine_mode new_mode
     311                 :        6673 :     = targetm.cc_modes_compatible (GET_MODE (compare), cmp->orig_mode);
     312                 :             : 
     313                 :        6673 :   if (new_mode == VOIDmode)
     314                 :             :     return false;
     315                 :             : 
     316                 :        6673 :   if (cmp->orig_mode != new_mode)
     317                 :             :     {
     318                 :             :       /* Generate new comparison for substitution.  */
     319                 :        1085 :       rtx flags = gen_rtx_REG (new_mode, targetm.flags_regnum);
     320                 :        1085 :       rtx x = gen_rtx_COMPARE (new_mode, cmp->in_a, cmp->in_b);
     321                 :        1085 :       x = gen_rtx_SET (flags, x);
     322                 :             : 
     323                 :        1085 :       if (!validate_change (cmp->insn, &PATTERN (cmp->insn), x, false))
     324                 :             :         return false;
     325                 :             : 
     326                 :        1085 :       cmp->orig_mode = new_mode;
     327                 :             :     }
     328                 :             : 
     329                 :             :   return true;
     330                 :             : }
     331                 :             : 
     332                 :             : /* Identify comparison instructions within BB.  If the flags from the last
     333                 :             :    compare in the BB is live at the end of the block, install the compare
     334                 :             :    in BB->AUX.  Called via dom_walker.walk ().  */
     335                 :             : 
     336                 :             : edge
     337                 :    10899999 : find_comparison_dom_walker::before_dom_children (basic_block bb)
     338                 :             : {
     339                 :    10899999 :   rtx_insn *insn, *next;
     340                 :    10899999 :   bool need_purge = false;
     341                 :    10899999 :   rtx_insn *last_setter[FIRST_PSEUDO_REGISTER];
     342                 :             : 
     343                 :             :   /* The last comparison that was made.  Will be reset to NULL
     344                 :             :      once the flags are clobbered.  */
     345                 :    10899999 :   struct comparison *last_cmp = NULL;
     346                 :             : 
     347                 :             :   /* True iff the last comparison has not been clobbered, nor
     348                 :             :      have its inputs.  Used to eliminate duplicate compares.  */
     349                 :    10899999 :   bool last_cmp_valid = false;
     350                 :             : 
     351                 :             :   /* The last insn that clobbered the flags, if that insn is of
     352                 :             :      a form that may be valid for eliminating a following compare.
     353                 :             :      To be reset to NULL once the flags are set otherwise.  */
     354                 :    10899999 :   rtx_insn *last_clobber = NULL;
     355                 :             : 
     356                 :             :   /* Propagate the last live comparison throughout the extended basic block. */
     357                 :    10899999 :   if (single_pred_p (bb))
     358                 :             :     {
     359                 :     7543666 :       last_cmp = (struct comparison *) single_pred (bb)->aux;
     360                 :     7543666 :       if (last_cmp)
     361                 :     3824221 :         last_cmp_valid = last_cmp->inputs_valid;
     362                 :             :     }
     363                 :             : 
     364                 :    10899999 :   memset (last_setter, 0, sizeof (last_setter));
     365                 :   123592545 :   for (insn = BB_HEAD (bb); insn; insn = next)
     366                 :             :     {
     367                 :   112692546 :       rtx src;
     368                 :             : 
     369                 :   112692546 :       next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn));
     370                 :   112692546 :       if (!NONDEBUG_INSN_P (insn))
     371                 :    58959554 :         continue;
     372                 :             : 
     373                 :    53732992 :       src = conforming_compare (insn);
     374                 :    53732992 :       if (src)
     375                 :             :         {
     376                 :     3046593 :           rtx eh_note = NULL;
     377                 :             : 
     378                 :     3046593 :           if (cfun->can_throw_non_call_exceptions)
     379                 :      590889 :             eh_note = find_reg_note (insn, REG_EH_REGION, NULL);
     380                 :             : 
     381                 :     3046593 :           if (last_cmp_valid && can_eliminate_compare (src, eh_note, last_cmp))
     382                 :             :             {
     383                 :        6673 :               if (eh_note)
     384                 :           0 :                 need_purge = true;
     385                 :        6673 :               delete_insn (insn);
     386                 :        6673 :               continue;
     387                 :             :             }
     388                 :             : 
     389                 :     3039920 :           last_cmp = XCNEW (struct comparison);
     390                 :     3039920 :           last_cmp->insn = insn;
     391                 :     3039920 :           last_cmp->prev_clobber = last_clobber;
     392                 :     3039920 :           last_cmp->in_a = strip_not (XEXP (src, 0));
     393                 :     3039920 :           last_cmp->in_b = XEXP (src, 1);
     394                 :     3039920 :           last_cmp->not_in_a = is_not (XEXP (src, 0));
     395                 :     3039920 :           last_cmp->eh_note = eh_note;
     396                 :     3039920 :           last_cmp->orig_mode = GET_MODE (src);
     397                 :     3039920 :           if (last_cmp->in_b == const0_rtx
     398                 :     3039920 :               && last_setter[REGNO (last_cmp->in_a)])
     399                 :             :             {
     400                 :      933253 :               rtx set = single_set (last_setter[REGNO (last_cmp->in_a)]);
     401                 :      933253 :               if (set && rtx_equal_p (SET_DEST (set), last_cmp->in_a))
     402                 :      860946 :                 last_cmp->in_a_setter = last_setter[REGNO (last_cmp->in_a)];
     403                 :             :             }
     404                 :     3039920 :           all_compares.safe_push (last_cmp);
     405                 :             : 
     406                 :             :           /* It's unusual, but be prepared for comparison patterns that
     407                 :             :              also clobber an input, or perhaps a scratch.  */
     408                 :     3039920 :           last_clobber = NULL;
     409                 :     3039920 :           last_cmp_valid = true;
     410                 :             :         }
     411                 :             : 
     412                 :             :       else
     413                 :             :         {
     414                 :             :           /* Notice if this instruction uses the flags register.  */
     415                 :    50686399 :           if (last_cmp)
     416                 :    12871252 :             find_flags_uses_in_insn (last_cmp, insn);
     417                 :             : 
     418                 :             :           /* Notice if this instruction kills the flags register.  */
     419                 :    50686399 :           df_ref def;
     420                 :   134088228 :           FOR_EACH_INSN_DEF (def, insn)
     421                 :    94262296 :             if (DF_REF_REGNO (def) == targetm.flags_regnum)
     422                 :             :               {
     423                 :             :                 /* See if this insn could be the "clobber" that eliminates
     424                 :             :                    a future comparison.   */
     425                 :    10860467 :                 last_clobber = (arithmetic_flags_clobber_p (insn)
     426                 :    10860467 :                                 ? insn : NULL);
     427                 :             : 
     428                 :             :                 /* In either case, the previous compare is no longer valid.  */
     429                 :    10860467 :                 last_cmp = NULL;
     430                 :    10860467 :                 last_cmp_valid = false;
     431                 :    10860467 :                 break;
     432                 :             :               }
     433                 :             :         }
     434                 :             : 
     435                 :             :       /* Notice if any of the inputs to the comparison have changed
     436                 :             :          and remember last insn that sets each register.  */
     437                 :    53726319 :       df_ref def;
     438                 :   454135179 :       FOR_EACH_INSN_DEF (def, insn)
     439                 :             :         {
     440                 :   400408860 :           if (last_cmp_valid
     441                 :   400408860 :               && (DF_REF_REGNO (def) == REGNO (last_cmp->in_a)
     442                 :     7225554 :                   || (REG_P (last_cmp->in_b)
     443                 :     1862910 :                       && DF_REF_REGNO (def) == REGNO (last_cmp->in_b))))
     444                 :             :             last_cmp_valid = false;
     445                 :   400408860 :           last_setter[DF_REF_REGNO (def)] = insn;
     446                 :             :         }
     447                 :             :     }
     448                 :             : 
     449                 :             :   /* Remember the live comparison for subsequent members of
     450                 :             :      the extended basic block.  */
     451                 :    10899999 :   if (last_cmp)
     452                 :             :     {
     453                 :     4121289 :       bb->aux = last_cmp;
     454                 :     4121289 :       last_cmp->inputs_valid = last_cmp_valid;
     455                 :             : 
     456                 :             :       /* Look to see if the flags register is live outgoing here, and
     457                 :             :          incoming to any successor not part of the extended basic block.  */
     458                 :     4121289 :       if (bitmap_bit_p (df_get_live_out (bb), targetm.flags_regnum))
     459                 :             :         {
     460                 :       17414 :           edge e;
     461                 :       17414 :           edge_iterator ei;
     462                 :             : 
     463                 :       51527 :           FOR_EACH_EDGE (e, ei, bb->succs)
     464                 :             :             {
     465                 :       34368 :               basic_block dest = e->dest;
     466                 :       34368 :               if (bitmap_bit_p (df_get_live_in (bb), targetm.flags_regnum)
     467                 :       35052 :                   && !single_pred_p (dest))
     468                 :             :                 {
     469                 :         255 :                   last_cmp->missing_uses = true;
     470                 :         255 :                   break;
     471                 :             :                 }
     472                 :             :             }
     473                 :             :         }
     474                 :             :     }
     475                 :             : 
     476                 :             :   /* If we deleted a compare with a REG_EH_REGION note, we may need to
     477                 :             :      remove EH edges.  */
     478                 :    10899999 :   if (need_purge)
     479                 :           0 :     purge_dead_edges (bb);
     480                 :             : 
     481                 :    10899999 :   return NULL;
     482                 :             : }
     483                 :             : 
     484                 :             : /* Find all comparisons in the function.  */
     485                 :             : 
     486                 :             : static void
     487                 :      987684 : find_comparisons (void)
     488                 :             : {
     489                 :      987684 :   calculate_dominance_info (CDI_DOMINATORS);
     490                 :             : 
     491                 :      987684 :   find_comparison_dom_walker (CDI_DOMINATORS)
     492                 :      987684 :     .walk (cfun->cfg->x_entry_block_ptr);
     493                 :             : 
     494                 :      987684 :   clear_aux_for_blocks ();
     495                 :      987684 :   free_dominance_info (CDI_DOMINATORS);
     496                 :      987684 : }
     497                 :             : 
     498                 :             : /* Select an alternate CC_MODE for a comparison insn comparing A and B.
     499                 :             :    Note that inputs are almost certainly different than the IN_A and IN_B
     500                 :             :    stored in CMP -- we're called while attempting to eliminate the compare
     501                 :             :    after all.  Return the new FLAGS rtx if successful, else return NULL.
     502                 :             :    Note that this function may start a change group.  */
     503                 :             : 
     504                 :             : static rtx
     505                 :      698262 : maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
     506                 :             :                       rtx b ATTRIBUTE_UNUSED)
     507                 :             : {
     508                 :      698262 :   machine_mode sel_mode;
     509                 :      698262 :   const int n = cmp->n_uses;
     510                 :      698262 :   rtx flags = NULL;
     511                 :             : 
     512                 :             : #ifndef SELECT_CC_MODE
     513                 :             :   /* Minimize code differences when this target macro is undefined.  */
     514                 :             :   return NULL;
     515                 :             : #define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
     516                 :             : #endif
     517                 :             : 
     518                 :             :   /* If we don't have access to all of the uses, we can't validate.  */
     519                 :      698262 :   if (cmp->missing_uses || n == 0)
     520                 :             :     return NULL;
     521                 :             : 
     522                 :             :   /* Find a new mode that works for all of the uses.  Special case the
     523                 :             :      common case of exactly one use.  */
     524                 :      697340 :   if (n == 1)
     525                 :             :     {
     526                 :      691151 :       sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
     527                 :      691151 :       if (sel_mode != cmp->orig_mode)
     528                 :             :         {
     529                 :        1560 :           flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
     530                 :        1560 :           validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
     531                 :             :         }
     532                 :             :     }
     533                 :             :   else
     534                 :             :     {
     535                 :        6189 :       int i;
     536                 :             : 
     537                 :        6189 :       sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
     538                 :       12392 :       for (i = 1; i < n; ++i)
     539                 :             :         {
     540                 :        6203 :           machine_mode new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
     541                 :        6203 :           if (new_mode != sel_mode)
     542                 :             :             {
     543                 :        6056 :               sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
     544                 :        6056 :               if (sel_mode == VOIDmode)
     545                 :             :                 return NULL;
     546                 :             :             }
     547                 :             :         }
     548                 :             : 
     549                 :        6189 :       if (sel_mode != cmp->orig_mode)
     550                 :             :         {
     551                 :           0 :           flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
     552                 :           0 :           for (i = 0; i < n; ++i)
     553                 :           0 :             validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
     554                 :             :         }
     555                 :             :     }
     556                 :             : 
     557                 :             :   return flags;
     558                 :             : }
     559                 :             : 
     560                 :             : /* Return a register RTX holding the same value at START as REG at END, or
     561                 :             :    NULL_RTX if there is none.  */
     562                 :             : 
     563                 :             : static rtx
     564                 :     1196787 : equivalent_reg_at_start (rtx reg, rtx_insn *end, rtx_insn *start)
     565                 :             : {
     566                 :     1196787 :   machine_mode orig_mode = GET_MODE (reg);
     567                 :     1196787 :   rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (end));
     568                 :             : 
     569                 :     2727793 :   for (rtx_insn *insn = PREV_INSN (end);
     570                 :     2727793 :        insn != start;
     571                 :     1531006 :        insn = PREV_INSN (insn))
     572                 :             :     {
     573                 :     1650085 :       const int abnormal_flags
     574                 :             :         = (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
     575                 :             :            | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
     576                 :             :            | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
     577                 :             :            | DF_REF_PRE_POST_MODIFY);
     578                 :     1650085 :       df_ref def;
     579                 :             : 
     580                 :             :       /* Note that the BB_HEAD is always either a note or a label, but in
     581                 :             :          any case it means that REG is defined outside the block.  */
     582                 :     1650085 :       if (insn == bb_head)
     583                 :             :         return NULL_RTX;
     584                 :     1650085 :       if (NOTE_P (insn) || DEBUG_INSN_P (insn))
     585                 :     1258248 :         continue;
     586                 :             : 
     587                 :             :       /* Find a possible def of REG in INSN.  */
     588                 :      571056 :       FOR_EACH_INSN_DEF (def, insn)
     589                 :      312433 :         if (DF_REF_REGNO (def) == REGNO (reg))
     590                 :             :           break;
     591                 :             : 
     592                 :             :       /* No definitions of REG; continue searching.  */
     593                 :      391837 :       if (def == NULL)
     594                 :      258623 :         continue;
     595                 :             : 
     596                 :             :       /* Bail if this is not a totally normal set of REG.  */
     597                 :      133214 :       if (DF_REF_IS_ARTIFICIAL (def))
     598                 :             :         return NULL_RTX;
     599                 :      133214 :       if (DF_REF_FLAGS (def) & abnormal_flags)
     600                 :             :         return NULL_RTX;
     601                 :             : 
     602                 :             :       /* We've found an insn between the compare and the clobber that sets
     603                 :             :          REG.  Given that pass_cprop_hardreg has not yet run, we still find
     604                 :             :          situations in which we can usefully look through a copy insn.  */
     605                 :      133199 :       rtx x = single_set (insn);
     606                 :      133199 :       if (x == NULL_RTX)
     607                 :             :         return NULL_RTX;
     608                 :      132819 :       reg = SET_SRC (x);
     609                 :      132819 :       if (!REG_P (reg))
     610                 :             :         return NULL_RTX;
     611                 :             :     }
     612                 :             : 
     613                 :     1077708 :   if (GET_MODE (reg) != orig_mode)
     614                 :             :     return NULL_RTX;
     615                 :             : 
     616                 :             :   return reg;
     617                 :             : }
     618                 :             : 
     619                 :             : /* Return true if it is okay to merge the comparison CMP_INSN with
     620                 :             :    the instruction ARITH_INSN.  Both instructions are assumed to be in the
     621                 :             :    same basic block with ARITH_INSN appearing before CMP_INSN.  This checks
     622                 :             :    that there are no uses or defs of the condition flags or control flow
     623                 :             :    changes between the two instructions.  */
     624                 :             : 
     625                 :             : static bool
     626                 :      860871 : can_merge_compare_into_arith (rtx_insn *cmp_insn, rtx_insn *arith_insn)
     627                 :             : {
     628                 :     2572317 :   for (rtx_insn *insn = PREV_INSN (cmp_insn);
     629                 :     2572317 :        insn && insn != arith_insn;
     630                 :     1711446 :        insn = PREV_INSN (insn))
     631                 :             :     {
     632                 :     1825218 :       if (!NONDEBUG_INSN_P (insn))
     633                 :     1496347 :         continue;
     634                 :             :       /* Bail if there are jumps or calls in between.  */
     635                 :      328871 :       if (!NONJUMP_INSN_P (insn))
     636                 :             :         return false;
     637                 :             : 
     638                 :             :       /* Bail on old-style asm statements because they lack
     639                 :             :          data flow information.  */
     640                 :      311498 :       if (GET_CODE (PATTERN (insn)) == ASM_INPUT)
     641                 :             :         return false;
     642                 :             : 
     643                 :      311497 :       df_ref ref;
     644                 :             :       /* Find a USE of the flags register.  */
     645                 :      734084 :       FOR_EACH_INSN_USE (ref, insn)
     646                 :      427830 :         if (DF_REF_REGNO (ref) == targetm.flags_regnum)
     647                 :             :           return false;
     648                 :             : 
     649                 :             :       /* Find a DEF of the flags register.  */
     650                 :      510279 :       FOR_EACH_INSN_DEF (ref, insn)
     651                 :      295180 :         if (DF_REF_REGNO (ref) == targetm.flags_regnum)
     652                 :             :           return false;
     653                 :             :     }
     654                 :             :   return true;
     655                 :             : }
     656                 :             : 
     657                 :             : /* Given two SET expressions, SET_A and SET_B determine whether they form
     658                 :             :    a recognizable pattern when emitted in parallel.  Return that parallel
     659                 :             :    if so.  Otherwise return NULL.  */
     660                 :             : 
     661                 :             : static rtx
     662                 :           2 : try_validate_parallel (rtx set_a, rtx set_b)
     663                 :             : {
     664                 :           2 :   rtx par = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b));
     665                 :           2 :   rtx_insn *insn = make_insn_raw (par);
     666                 :             : 
     667                 :           2 :   if (insn_invalid_p (insn, false))
     668                 :             :     {
     669                 :           2 :       crtl->emit.x_cur_insn_uid--;
     670                 :           2 :       return NULL_RTX;
     671                 :             :     }
     672                 :             : 
     673                 :           0 :   SET_PREV_INSN (insn) = NULL_RTX;
     674                 :           0 :   SET_NEXT_INSN (insn) = NULL_RTX;
     675                 :           0 :   INSN_LOCATION (insn) = 0;
     676                 :           0 :   return insn;
     677                 :             : }
     678                 :             : 
     679                 :             : /* For a comparison instruction described by CMP check if it compares a
     680                 :             :    register with zero i.e. it is of the form CC := CMP R1, 0.
     681                 :             :    If it is, find the instruction defining R1 (say I1) and try to create a
     682                 :             :    PARALLEL consisting of I1 and the comparison, representing a flag-setting
     683                 :             :    arithmetic instruction.  Example:
     684                 :             :    I1: R1 := R2 + R3
     685                 :             :    <instructions that don't read the condition register>
     686                 :             :    I2: CC := CMP R1 0
     687                 :             :    I2 can be merged with I1 into:
     688                 :             :    I1: { CC := CMP (R2 + R3) 0 ; R1 := R2 + R3 }
     689                 :             :    This catches cases where R1 is used between I1 and I2 and therefore
     690                 :             :    combine and other RTL optimisations will not try to propagate it into
     691                 :             :    I2.  Return true if we succeeded in merging CMP.  */
     692                 :             : 
     693                 :             : static bool
     694                 :     3039920 : try_merge_compare (struct comparison *cmp)
     695                 :             : {
     696                 :     3039920 :   rtx_insn *cmp_insn = cmp->insn;
     697                 :             : 
     698                 :     3039920 :   if (cmp->in_b != const0_rtx || cmp->in_a_setter == NULL)
     699                 :             :     return false;
     700                 :      860946 :   rtx in_a = cmp->in_a;
     701                 :      860946 :   df_ref use;
     702                 :             : 
     703                 :      860946 :   FOR_EACH_INSN_USE (use, cmp_insn)
     704                 :      860946 :     if (DF_REF_REGNO (use) == REGNO (in_a))
     705                 :             :       break;
     706                 :      860946 :   if (!use)
     707                 :             :     return false;
     708                 :             : 
     709                 :      860946 :   rtx_insn *def_insn = cmp->in_a_setter;
     710                 :      860946 :   rtx set = single_set (def_insn);
     711                 :      860946 :   if (!set)
     712                 :             :     return false;
     713                 :             : 
     714                 :      860871 :   if (!can_merge_compare_into_arith (cmp_insn, def_insn))
     715                 :             :     return false;
     716                 :             : 
     717                 :      747099 :   rtx src = SET_SRC (set);
     718                 :             : 
     719                 :             :   /* If the source uses addressing modes with side effects, we can't
     720                 :             :      do the merge because we'd end up with a PARALLEL that has two
     721                 :             :      instances of that side effect in it.  */
     722                 :      747099 :   if (side_effects_p (src))
     723                 :             :     return false;
     724                 :             : 
     725                 :      367114 :   rtx flags = maybe_select_cc_mode (cmp, src, CONST0_RTX (GET_MODE (src)));
     726                 :      367114 :   if (!flags)
     727                 :             :     {
     728                 :             :     /* We may already have a change group going through maybe_select_cc_mode.
     729                 :             :        Discard it properly.  */
     730                 :      367112 :       cancel_changes (0);
     731                 :      367112 :       return false;
     732                 :             :     }
     733                 :             : 
     734                 :           2 :   rtx flag_set
     735                 :           2 :     = gen_rtx_SET (flags, gen_rtx_COMPARE (GET_MODE (flags),
     736                 :             :                                            copy_rtx (src),
     737                 :             :                                            CONST0_RTX (GET_MODE (src))));
     738                 :           2 :   rtx arith_set = copy_rtx (PATTERN (def_insn));
     739                 :           2 :   rtx par = try_validate_parallel (flag_set, arith_set);
     740                 :           2 :   if (!par)
     741                 :             :     {
     742                 :             :       /* We may already have a change group going through maybe_select_cc_mode.
     743                 :             :          Discard it properly.  */
     744                 :           2 :       cancel_changes (0);
     745                 :           2 :       return false;
     746                 :             :     }
     747                 :           0 :   if (!apply_change_group ())
     748                 :             :     return false;
     749                 :           0 :   emit_insn_after (par, def_insn);
     750                 :           0 :   delete_insn (def_insn);
     751                 :           0 :   delete_insn (cmp->insn);
     752                 :           0 :   return true;
     753                 :             : }
     754                 :             : 
     755                 :             : /* Attempt to replace a comparison with a prior arithmetic insn that can
     756                 :             :    compute the same flags value as the comparison itself.  Return true if
     757                 :             :    successful, having made all rtl modifications necessary.  */
     758                 :             : 
     759                 :             : static bool
     760                 :     3039920 : try_eliminate_compare (struct comparison *cmp)
     761                 :             : {
     762                 :     3039920 :   rtx flags, in_a, in_b, cmp_a, cmp_b;
     763                 :             : 
     764                 :     3039920 :   if (try_merge_compare (cmp))
     765                 :             :     return true;
     766                 :             : 
     767                 :             :   /* We must have found an interesting "clobber" preceding the compare.  */
     768                 :     3039920 :   if (cmp->prev_clobber == NULL)
     769                 :             :     return false;
     770                 :             : 
     771                 :             :   /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
     772                 :             :      Given that this target requires this pass, we can assume that most
     773                 :             :      insns do clobber the flags, and so the distance between the compare
     774                 :             :      and the clobber is likely to be small.  */
     775                 :             :   /* ??? This is one point at which one could argue that DF_REF_CHAIN would
     776                 :             :      be useful, but it is thought to be too heavy-weight a solution here.  */
     777                 :      850529 :   in_a = equivalent_reg_at_start (cmp->in_a, cmp->insn, cmp->prev_clobber);
     778                 :      850529 :   if (!in_a)
     779                 :             :     return false;
     780                 :             : 
     781                 :             :   /* Likewise for IN_B if need be.  */
     782                 :      777185 :   if (CONSTANT_P (cmp->in_b))
     783                 :             :     in_b = cmp->in_b;
     784                 :      346258 :   else if (REG_P (cmp->in_b))
     785                 :             :     {
     786                 :      346258 :       in_b = equivalent_reg_at_start (cmp->in_b, cmp->insn, cmp->prev_clobber);
     787                 :      346258 :       if (!in_b)
     788                 :             :         return false;
     789                 :             :     }
     790                 :           0 :   else if (GET_CODE (cmp->in_b) == UNSPEC)
     791                 :             :     {
     792                 :           0 :       const int len = XVECLEN (cmp->in_b, 0);
     793                 :           0 :       rtvec v = rtvec_alloc (len);
     794                 :           0 :       for (int i = 0; i < len; i++)
     795                 :             :         {
     796                 :           0 :           rtx r = equivalent_reg_at_start (XVECEXP (cmp->in_b, 0, i),
     797                 :             :                                            cmp->insn, cmp->prev_clobber);
     798                 :           0 :           if (!r)
     799                 :             :             return false;
     800                 :           0 :           RTVEC_ELT (v, i) = r;
     801                 :             :         }
     802                 :           0 :       in_b = gen_rtx_UNSPEC (GET_MODE (cmp->in_b), v, XINT (cmp->in_b, 1));
     803                 :             :     }
     804                 :             :   else
     805                 :           0 :     gcc_unreachable ();
     806                 :             : 
     807                 :             :   /* We've reached PREV_CLOBBER without finding a modification of IN_A.
     808                 :             :      Validate that PREV_CLOBBER itself does in fact refer to IN_A.  Do
     809                 :             :      recall that we've already validated the shape of PREV_CLOBBER.  */
     810                 :      731242 :   rtx_insn *insn = cmp->prev_clobber;
     811                 :             : 
     812                 :      731242 :   rtx x = XVECEXP (PATTERN (insn), 0, 0);
     813                 :      731242 :   if (rtx_equal_p (SET_DEST (x), in_a))
     814                 :      328356 :     cmp_a = SET_SRC (x);
     815                 :             : 
     816                 :             :   /* Also check operations with implicit extensions, e.g.:
     817                 :             :      [(set (reg:DI)
     818                 :             :            (zero_extend:DI (plus:SI (reg:SI) (reg:SI))))
     819                 :             :       (set (reg:CCZ flags)
     820                 :             :            (compare:CCZ (plus:SI (reg:SI) (reg:SI))
     821                 :             :                         (const_int 0)))] */
     822                 :      402886 :   else if (REG_P (SET_DEST (x))
     823                 :      402886 :            && REG_P (in_a)
     824                 :      402886 :            && REGNO (SET_DEST (x)) == REGNO (in_a)
     825                 :       19755 :            && (GET_CODE (SET_SRC (x)) == ZERO_EXTEND
     826                 :       19755 :                || GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
     827                 :      405678 :            && GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
     828                 :             :     cmp_a = XEXP (SET_SRC (x), 0);
     829                 :             : 
     830                 :             :   /* Also check fully redundant comparisons, e.g.:
     831                 :             :      [(set (reg:SI)
     832                 :             :            (minus:SI (reg:SI) (reg:SI))))
     833                 :             :       (set (reg:CC flags)
     834                 :             :            (compare:CC (reg:SI) (reg:SI)))] */
     835                 :      400094 :   else if (REG_P (in_b)
     836                 :      201812 :            && GET_CODE (SET_SRC (x)) == MINUS
     837                 :       13508 :            && rtx_equal_p (XEXP (SET_SRC (x), 0), in_a)
     838                 :      400094 :            && rtx_equal_p (XEXP (SET_SRC (x), 1), in_b))
     839                 :             :     cmp_a = in_a;
     840                 :             : 
     841                 :             :   else
     842                 :      400094 :     return false;
     843                 :             : 
     844                 :             :   /* If the source uses addressing modes with side effects, we can't
     845                 :             :      do the merge because we'd end up with a PARALLEL that has two
     846                 :             :      instances of that side effect in it.  */
     847                 :      331148 :   if (side_effects_p (cmp_a))
     848                 :             :     return false;
     849                 :             : 
     850                 :      331148 :   if (in_a == in_b)
     851                 :             :     cmp_b = cmp_a;
     852                 :      331144 :   else if (rtx_equal_p (SET_DEST (x), in_b))
     853                 :           0 :     cmp_b = SET_SRC (x);
     854                 :             :   else
     855                 :             :     cmp_b = in_b;
     856                 :      331148 :   if (side_effects_p (cmp_b))
     857                 :             :     return false;
     858                 :             : 
     859                 :             :   /* Determine if we ought to use a different CC_MODE here.  */
     860                 :      331148 :   flags = maybe_select_cc_mode (cmp, cmp_a, cmp_b);
     861                 :      331148 :   if (flags == NULL)
     862                 :      329590 :     flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
     863                 :             : 
     864                 :             :   /* Generate a new comparison for installation in the setter.  */
     865                 :      331148 :   rtx y = cmp->not_in_a
     866                 :      331148 :           ? gen_rtx_NOT (GET_MODE (cmp_a), copy_rtx (cmp_a))
     867                 :      331148 :           : copy_rtx (cmp_a);
     868                 :      331148 :   y = gen_rtx_COMPARE (GET_MODE (flags), y, copy_rtx (cmp_b));
     869                 :      331148 :   y = gen_rtx_SET (flags, y);
     870                 :             : 
     871                 :             :   /* Canonicalize instruction to:
     872                 :             :      [(set (reg:CCM) (compare:CCM (operation) (immediate)))
     873                 :             :       (set (reg) (operation)]  */
     874                 :             : 
     875                 :      331148 :   rtvec v = rtvec_alloc (2);
     876                 :      331148 :   RTVEC_ELT (v, 0) = y;
     877                 :      331148 :   RTVEC_ELT (v, 1) = x;
     878                 :             :   
     879                 :      331148 :   rtx pat = gen_rtx_PARALLEL (VOIDmode, v);
     880                 :             :   
     881                 :             :   /* Succeed if the new instruction is valid.  Note that we may have started
     882                 :             :      a change group within maybe_select_cc_mode, therefore we must continue. */
     883                 :      331148 :   validate_change (insn, &PATTERN (insn), pat, true);
     884                 :             :   
     885                 :      331148 :   if (!apply_change_group ())
     886                 :             :     return false;
     887                 :             : 
     888                 :             :   /* Success.  Delete the compare insn...  */
     889                 :       25320 :   delete_insn (cmp->insn);
     890                 :             : 
     891                 :             :   /* ... and any notes that are now invalid due to multiple sets.  */
     892                 :       25320 :   x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
     893                 :       25320 :   if (x)
     894                 :           0 :     remove_note (insn, x);
     895                 :       25320 :   x = find_reg_note (insn, REG_EQUAL, NULL);
     896                 :       25320 :   if (x)
     897                 :        4442 :     remove_note (insn, x);
     898                 :       25320 :   x = find_reg_note (insn, REG_EQUIV, NULL);
     899                 :       25320 :   if (x)
     900                 :           0 :     remove_note (insn, x);
     901                 :             : 
     902                 :             :   return true;
     903                 :             : }
     904                 :             : 
     905                 :             : /* Main entry point to the pass.  */
     906                 :             : 
     907                 :             : static unsigned int
     908                 :      987684 : execute_compare_elim_after_reload (void)
     909                 :             : {
     910                 :      987684 :   df_set_flags (DF_LR_RUN_DCE);
     911                 :      987684 :   df_analyze ();
     912                 :             : 
     913                 :      987684 :   gcc_checking_assert (!all_compares.exists ());
     914                 :             : 
     915                 :             :   /* Locate all comparisons and their uses, and eliminate duplicates.  */
     916                 :      987684 :   find_comparisons ();
     917                 :      987684 :   if (all_compares.exists ())
     918                 :             :     {
     919                 :             :       struct comparison *cmp;
     920                 :             :       size_t i;
     921                 :             : 
     922                 :             :       /* Eliminate comparisons that are redundant with flags computation.  */
     923                 :     3472821 :       FOR_EACH_VEC_ELT (all_compares, i, cmp)
     924                 :             :         {
     925                 :     3039920 :           try_eliminate_compare (cmp);
     926                 :     3039920 :           XDELETE (cmp);
     927                 :             :         }
     928                 :             : 
     929                 :      432901 :       all_compares.release ();
     930                 :             :     }
     931                 :             : 
     932                 :      987684 :   return 0;
     933                 :             : }
     934                 :             : 
     935                 :             : namespace {
     936                 :             : 
     937                 :             : const pass_data pass_data_compare_elim_after_reload =
     938                 :             : {
     939                 :             :   RTL_PASS, /* type */
     940                 :             :   "cmpelim", /* name */
     941                 :             :   OPTGROUP_NONE, /* optinfo_flags */
     942                 :             :   TV_NONE, /* tv_id */
     943                 :             :   0, /* properties_required */
     944                 :             :   0, /* properties_provided */
     945                 :             :   0, /* properties_destroyed */
     946                 :             :   0, /* todo_flags_start */
     947                 :             :   ( TODO_df_finish | TODO_df_verify ), /* todo_flags_finish */
     948                 :             : };
     949                 :             : 
     950                 :             : class pass_compare_elim_after_reload : public rtl_opt_pass
     951                 :             : {
     952                 :             : public:
     953                 :      281914 :   pass_compare_elim_after_reload (gcc::context *ctxt)
     954                 :      563828 :     : rtl_opt_pass (pass_data_compare_elim_after_reload, ctxt)
     955                 :             :   {}
     956                 :             : 
     957                 :             :   /* opt_pass methods: */
     958                 :     1426773 :   bool gate (function *) final override
     959                 :             :     {
     960                 :             :       /* Setting this target hook value is how a backend indicates the need.  */
     961                 :     1426773 :       if (targetm.flags_regnum == INVALID_REGNUM)
     962                 :             :         return false;
     963                 :     1426773 :       return flag_compare_elim_after_reload;
     964                 :             :     }
     965                 :             : 
     966                 :      987684 :   unsigned int execute (function *) final override
     967                 :             :     {
     968                 :      987684 :       return execute_compare_elim_after_reload ();
     969                 :             :     }
     970                 :             : 
     971                 :             : }; // class pass_compare_elim_after_reload
     972                 :             : 
     973                 :             : } // anon namespace
     974                 :             : 
     975                 :             : rtl_opt_pass *
     976                 :      281914 : make_pass_compare_elim_after_reload (gcc::context *ctxt)
     977                 :             : {
     978                 :      281914 :   return new pass_compare_elim_after_reload (ctxt);
     979                 :             : }
        

Generated by: LCOV version 2.1-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.