LCOV - code coverage report
Current view: top level - gcc - gimple-isel.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.0 % 637 586
Test Date: 2026-08-22 16:33:35 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Schedule GIMPLE vector statements.
       2              :    Copyright (C) 2020-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it
       7              : under the terms of the GNU General Public License as published by the
       8              : Free Software Foundation; either version 3, or (at your option) any
       9              : later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT
      12              : ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "backend.h"
      24              : #include "rtl.h"
      25              : #include "tree.h"
      26              : #include "gimple.h"
      27              : #include "tree-pass.h"
      28              : #include "ssa.h"
      29              : #include "expmed.h"
      30              : #include "optabs-tree.h"
      31              : #include "tree-eh.h"
      32              : #include "gimple-iterator.h"
      33              : #include "gimplify-me.h"
      34              : #include "gimplify.h"
      35              : #include "tree-cfg.h"
      36              : #include "bitmap.h"
      37              : #include "tree-ssa-dce.h"
      38              : #include "memmodel.h"
      39              : #include "optabs.h"
      40              : #include "gimple-fold.h"
      41              : #include "internal-fn.h"
      42              : #include "fold-const.h"
      43              : #include "gimple-range.h"
      44              : 
      45              : 
      46              : /* Expand all ARRAY_REF(VIEW_CONVERT_EXPR) gimple assignments into calls to
      47              :    internal function based on vector type of selected expansion.
      48              : 
      49              :    For vec_set:
      50              : 
      51              :      VIEW_CONVERT_EXPR<int[4]>(u)[_1] = i_4(D);
      52              :    =>
      53              :      _7 = u;
      54              :      _8 = .VEC_SET (_7, i_4(D), _1);
      55              :      u = _8;
      56              : 
      57              :    For vec_extract:
      58              : 
      59              :       _3 = VIEW_CONVERT_EXPR<intD.1[4]>(vD.2208)[idx_2(D)];
      60              :    =>
      61              :       _4 = vD.2208;
      62              :       _3 = .VEC_EXTRACT (_4, idx_2(D));  */
      63              : 
      64              : static bool
      65    102495153 : gimple_expand_vec_set_extract_expr (struct function *fun,
      66              :                                     gimple_stmt_iterator *gsi)
      67              : {
      68    102495153 :   gcall *new_stmt = NULL;
      69    102495153 :   gassign *ass_stmt = NULL;
      70    102495153 :   bool cfg_changed = false;
      71              : 
      72              :   /* Only consider code == GIMPLE_ASSIGN.  */
      73    102495153 :   gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
      74     32757988 :   if (!stmt)
      75              :     return false;
      76              : 
      77     32757988 :   bool is_extract = false;
      78              : 
      79     32757988 :   tree lhs = gimple_assign_lhs (stmt);
      80     32757988 :   tree rhs = gimple_assign_rhs1 (stmt);
      81     32757988 :   tree val, ref;
      82     32757988 :   if (TREE_CODE (lhs) == ARRAY_REF)
      83              :     {
      84              :       /* Assume it is a vec_set.  */
      85              :       val = rhs;
      86              :       ref = lhs;
      87              :     }
      88     32124818 :   else if (TREE_CODE (rhs) == ARRAY_REF)
      89              :     {
      90              :       /* vec_extract.  */
      91              :       is_extract = true;
      92              :       val = lhs;
      93              :       ref = rhs;
      94              :     }
      95              :   else
      96              :     return false;
      97              : 
      98      1212472 :   tree op0 = TREE_OPERAND (ref, 0);
      99      1212472 :   if (TREE_CODE (op0) == VIEW_CONVERT_EXPR
     100        33069 :       && DECL_P (TREE_OPERAND (op0, 0))
     101        27731 :       && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
     102      1232600 :       && (TYPE_MODE (TREE_TYPE (ref))
     103        10064 :           == TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0))))))
     104              :     {
     105        10060 :       tree pos = TREE_OPERAND (ref, 1);
     106              : 
     107        10060 :       tree view_op0 = TREE_OPERAND (op0, 0);
     108              : 
     109        10060 :       tree idx = TREE_OPERAND (ref, 1);
     110              :       // if index is a constant, then check the bounds
     111        10060 :       poly_uint64 idx_poly;
     112        10060 :       if (poly_int_tree_p (idx, &idx_poly))
     113              :         {
     114           33 :           poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (view_op0));
     115           33 :           if (known_ge (idx_poly, nelts))
     116           33 :             return false;
     117              :         }
     118        10027 :       else if (poly_int_tree_p (idx))
     119              :         // if idx doesn't fit into poly_uint64, but is constant, it
     120              :         // must be out of bounds
     121              :         return false;
     122        10020 :       machine_mode outermode = TYPE_MODE (TREE_TYPE (view_op0));
     123        10020 :       machine_mode extract_mode = TYPE_MODE (TREE_TYPE (ref));
     124              : 
     125        10020 :       if ((auto_var_in_fn_p (view_op0, fun->decl)
     126         1311 :            || (VAR_P (view_op0) && DECL_HARD_REGISTER (view_op0)))
     127         8719 :           && !TREE_ADDRESSABLE (view_op0)
     128        17010 :           && ((!is_extract && can_vec_set_var_idx_p (outermode))
     129              :               || (is_extract
     130         6783 :                   && can_vec_extract_var_idx_p (outermode, extract_mode))))
     131              :         {
     132          123 :           location_t loc = gimple_location (stmt);
     133          123 :           tree var_src = make_ssa_name (TREE_TYPE (view_op0));
     134              : 
     135          123 :           ass_stmt = gimple_build_assign (var_src, view_op0);
     136          246 :           gimple_set_vuse (ass_stmt, gimple_vuse (stmt));
     137          123 :           gimple_set_location (ass_stmt, loc);
     138          123 :           gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
     139              : 
     140          123 :           if (!is_extract)
     141              :             {
     142          123 :               tree var_dst = make_ssa_name (TREE_TYPE (view_op0));
     143              : 
     144          123 :               new_stmt = gimple_build_call_internal (IFN_VEC_SET, 3, var_src,
     145              :                                                      val, pos);
     146              : 
     147          123 :               gimple_call_set_lhs (new_stmt, var_dst);
     148          123 :               gimple_set_location (new_stmt, loc);
     149          123 :               gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
     150              : 
     151          123 :               ass_stmt = gimple_build_assign (view_op0, var_dst);
     152          123 :               gimple_set_location (ass_stmt, loc);
     153          123 :               gimple_move_vops (ass_stmt, stmt);
     154          123 :               gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
     155              : 
     156          123 :               basic_block bb = gimple_bb (stmt);
     157          123 :               if (gsi_remove (gsi, true)
     158          123 :                   && gimple_purge_dead_eh_edges (bb))
     159              :                 cfg_changed = true;
     160          123 :               *gsi = gsi_for_stmt (ass_stmt);
     161              :             }
     162              :           else
     163              :             {
     164            0 :               new_stmt
     165            0 :                 = gimple_build_call_internal (IFN_VEC_EXTRACT, 2, var_src, pos);
     166            0 :               gimple_call_set_lhs (new_stmt, lhs);
     167              : 
     168            0 :               gsi_replace (gsi, new_stmt, true);
     169            0 :               cfg_changed = true;
     170              :             }
     171              :         }
     172              :     }
     173              : 
     174              :   return cfg_changed;
     175              : }
     176              : 
     177              : /* Expand all VEC_COND_EXPR gimple assignments into calls to internal
     178              :    function based on type of selected expansion.  */
     179              : 
     180              : static gimple *
     181    102495153 : gimple_expand_vec_cond_expr (gimple_stmt_iterator *gsi)
     182              : {
     183    102495153 :   tree lhs, op0a = NULL_TREE;
     184    102495153 :   enum tree_code code;
     185    102495153 :   enum tree_code tcode;
     186              : 
     187              :   /* Only consider code == GIMPLE_ASSIGN.  */
     188    102495153 :   gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
     189     32767649 :   if (!stmt)
     190              :     return NULL;
     191              : 
     192     32767649 :   code = gimple_assign_rhs_code (stmt);
     193     32767649 :   if (code != VEC_COND_EXPR)
     194              :     return NULL;
     195              : 
     196        22602 :   tree op0 = gimple_assign_rhs1 (stmt);
     197        22602 :   tree op1 = gimple_assign_rhs2 (stmt);
     198        22602 :   tree op2 = gimple_assign_rhs3 (stmt);
     199        22602 :   lhs = gimple_assign_lhs (stmt);
     200        22602 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
     201              : 
     202              :   /* Lower mask typed, non-vector mode VEC_COND_EXPRs to bitwise operations.
     203              :      Those can end up generated by folding and at least for integer mode masks
     204              :      we cannot expect vcond expanders to exist.  We lower a ? b : c
     205              :      to (b & a) | (c & ~a).  */
     206        45204 :   if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (lhs))
     207        22604 :       && !VECTOR_MODE_P (mode))
     208              :     {
     209            0 :       gcc_assert (types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)));
     210            0 :       gimple_seq stmts = NULL;
     211            0 :       tree type = TREE_TYPE (lhs);
     212            0 :       location_t loc = gimple_location (stmt);
     213            0 :       tree tem0 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op1, op0);
     214            0 :       tree tem1 = gimple_build (&stmts, loc, BIT_NOT_EXPR, type, op0);
     215            0 :       tree tem2 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op2, tem1);
     216            0 :       tree tem3 = gimple_build (&stmts, loc, BIT_IOR_EXPR, type, tem0, tem2);
     217            0 :       gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
     218            0 :       return gimple_build_assign (lhs, tem3);
     219              :     }
     220              : 
     221        22602 :   bool can_compute_op0 = true;
     222        22602 :   gcc_assert (!COMPARISON_CLASS_P (op0));
     223        22602 :   if (TREE_CODE (op0) == SSA_NAME)
     224              :     {
     225        21266 :       gassign *def_stmt = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (op0));
     226        21255 :       if (def_stmt)
     227              :         {
     228        21255 :           tcode = gimple_assign_rhs_code (def_stmt);
     229        21255 :           op0a = gimple_assign_rhs1 (def_stmt);
     230              : 
     231        21255 :           tree op0_type = TREE_TYPE (op0);
     232        21255 :           tree op0a_type = TREE_TYPE (op0a);
     233        21255 :           if (TREE_CODE_CLASS (tcode) == tcc_comparison)
     234        16417 :             can_compute_op0 = expand_vec_cmp_expr_p (op0a_type, op0_type,
     235              :                                                      tcode);
     236        16417 :           gcc_assert (can_compute_op0);
     237              : 
     238        21255 :           if (can_compute_op0
     239        21255 :               && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (TREE_TYPE (op0)))
     240              :             {
     241              :               /* Assuming c = x CMP y.  */
     242        16264 :               bool op1_minus_onep = integer_minus_onep (op1);
     243        16264 :               bool op2_zerop = integer_zerop (op2);
     244        16264 :               tree vtype = TREE_TYPE (lhs);
     245        16264 :               machine_mode vmode = TYPE_MODE (vtype);
     246              :               /* Try to fold r = c ? -1 : 0 to r = c.  */
     247        16264 :               if (op1_minus_onep && op2_zerop)
     248              :                 {
     249         5980 :                   tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
     250         5980 :                   return gimple_build_assign (lhs, conv_op);
     251              :                 }
     252              :               /* Try to fold r = c ? -1 : z to r = c | z, or
     253              :                  r = c ? c : z.  */
     254        10284 :               if (op1_minus_onep)
     255              :                 {
     256           30 :                   tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
     257           30 :                   tree new_op1 = make_ssa_name (vtype);
     258           30 :                   gassign *new_stmt = gimple_build_assign (new_op1, conv_op);
     259           30 :                   gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
     260           30 :                   if (optab_handler (ior_optab, vmode) != CODE_FOR_nothing)
     261              :                     /* r = c | z */
     262           30 :                     return gimple_build_assign (lhs, BIT_IOR_EXPR, new_op1,
     263           30 :                                                 op2);
     264              :                   /* r = c ? c : z */
     265              :                   op1 = new_op1;
     266              :                 }
     267              :               /* Try to fold r = c ? z : 0 to r = c & z, or
     268              :                  r = c ? z : c.  */
     269        10254 :               else if (op2_zerop)
     270              :                 {
     271         6931 :                   tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
     272         6931 :                   tree new_op2 = make_ssa_name (vtype);
     273         6931 :                   gassign *new_stmt = gimple_build_assign (new_op2, conv_op);
     274         6931 :                   gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
     275         6931 :                   if (optab_handler (and_optab, vmode) != CODE_FOR_nothing)
     276              :                     /* r = c | z */
     277         6931 :                     return gimple_build_assign (lhs, BIT_AND_EXPR, new_op2,
     278         6931 :                                                 op1);
     279              :                   /* r = c ? z : c */
     280              :                   op2 = new_op2;
     281              :                 }
     282         3323 :               bool op1_zerop = integer_zerop (op1);
     283         3323 :               bool op2_minus_onep = integer_minus_onep (op2);
     284              :               /* Try to fold r = c ? 0 : z to r = .BIT_ANDN (z, c).  */
     285         3323 :               if (op1_zerop
     286         3323 :                   && (direct_internal_fn_supported_p (IFN_BIT_ANDN, vtype,
     287              :                                                       OPTIMIZE_FOR_BOTH)))
     288              :                 {
     289          559 :                   tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
     290          559 :                   tree new_op = make_ssa_name (vtype);
     291          559 :                   gassign *new_stmt = gimple_build_assign (new_op, conv_op);
     292          559 :                   gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
     293          559 :                   return gimple_build_call_internal (IFN_BIT_ANDN, 2, op2,
     294          559 :                                                      new_op);
     295              :                 }
     296              :               /* Try to fold r = c ? z : -1 to r = .BIT_IORN (z, c).  */
     297         2764 :               else if (op2_minus_onep
     298         2764 :                        && (direct_internal_fn_supported_p (IFN_BIT_IORN, vtype,
     299              :                                                            OPTIMIZE_FOR_BOTH)))
     300              :                 {
     301            0 :                   tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
     302            0 :                   tree new_op = make_ssa_name (vtype);
     303            0 :                   gassign *new_stmt = gimple_build_assign (new_op, conv_op);
     304            0 :                   gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
     305            0 :                   return gimple_build_call_internal (IFN_BIT_IORN, 2, op1,
     306            0 :                                                      new_op);
     307              :                 }
     308              :             }
     309              :         }
     310              :     }
     311              : 
     312         9102 :   gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0)));
     313        18204 :   gcc_assert (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0)))
     314              :               != CODE_FOR_nothing);
     315         9102 :   return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2);
     316              : }
     317              : 
     318              : /* Duplicate COND_EXPR condition defs of STMT located in BB when they are
     319              :    comparisons so RTL expansion with the help of TER
     320              :    can perform better if conversion.  */
     321              : static void
     322       589297 : maybe_duplicate_comparison (gassign *stmt, basic_block bb)
     323              : {
     324       589297 :   imm_use_iterator imm_iter;
     325       589297 :   use_operand_p use_p;
     326       589297 :   auto_vec<gassign *, 4> cond_exprs;
     327       589297 :   tree lhs = gimple_assign_lhs (stmt);
     328       589297 :   unsigned cnt = 0;
     329              : 
     330              :   /* This is should not be used for -O0 nor it is not useful
     331              :      when ter is turned off. */
     332       589297 :   if (!optimize || !flag_tree_ter)
     333              :     return;
     334              : 
     335       955815 :   FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
     336              :     {
     337       493536 :       if (is_gimple_debug (USE_STMT (use_p)))
     338        13896 :         continue;
     339       479640 :       cnt++;
     340              :       /* Add the use statement if it was a cond_expr.  */
     341       479640 :       if (gimple_bb (USE_STMT (use_p)) == bb
     342       432068 :           && is_gimple_assign (USE_STMT (use_p))
     343       411553 :           && gimple_assign_rhs_code (USE_STMT (use_p)) == COND_EXPR
     344       495491 :           && gimple_assign_rhs1_ptr (USE_STMT (use_p)) == use_p->use)
     345        15441 :         cond_exprs.safe_push (as_a <gassign *> (USE_STMT (use_p)));
     346       462279 :     }
     347              : 
     348              :   /* If the comparison has 0 or 1 uses, no reason to do anything. */
     349       462279 :   if (cnt <= 1)
     350              :     return;
     351              : 
     352              :   /* If we only use the expression inside cond_exprs in that BB, we don't
     353              :      need to duplicate for one of them so pop the top. */
     354        23120 :   if (cond_exprs.length () == cnt)
     355          203 :     cond_exprs.pop();
     356              : 
     357        23604 :   while (!cond_exprs.is_empty())
     358              :     {
     359          484 :       auto old_top = cond_exprs.pop();
     360          484 :       gassign *copy = as_a <gassign *> (gimple_copy (stmt));
     361          484 :       tree new_def = duplicate_ssa_name (lhs, copy);
     362          484 :       gimple_assign_set_lhs (copy, new_def);
     363          484 :       auto gsi2 = gsi_for_stmt (old_top);
     364          484 :       gsi_insert_before (&gsi2, copy, GSI_SAME_STMT);
     365          484 :       gimple_assign_set_rhs1 (old_top, new_def);
     366          484 :       update_stmt (old_top);
     367              :     }
     368       589297 : }
     369              : 
     370              : /* match.pd function to match atomic_bit_test_and pattern which
     371              :    has nop_convert:
     372              :      _1 = __atomic_fetch_or_4 (&v, 1, 0);
     373              :      _2 = (int) _1;
     374              :      _5 = _2 & 1;
     375              :  */
     376              : extern bool gimple_nop_atomic_bit_test_and_p (tree, tree *,
     377              :                                               tree (*) (tree));
     378              : extern bool gimple_nop_convert (tree, tree*, tree (*) (tree));
     379              : 
     380              : namespace {
     381              : 
     382              : const pass_data pass_data_gimple_isel =
     383              : {
     384              :   GIMPLE_PASS, /* type */
     385              :   "isel", /* name */
     386              :   OPTGROUP_VEC, /* optinfo_flags */
     387              :   TV_NONE, /* tv_id */
     388              :   PROP_cfg, /* properties_required */
     389              :   0, /* properties_provided */
     390              :   0, /* properties_destroyed */
     391              :   0, /* todo_flags_start */
     392              :   TODO_update_ssa, /* todo_flags_finish */
     393              : };
     394              : 
     395              : class pass_gimple_isel : public gimple_opt_pass
     396              : {
     397              : public:
     398       294196 :   pass_gimple_isel (gcc::context *ctxt)
     399       588392 :     : gimple_opt_pass (pass_data_gimple_isel, ctxt)
     400              :   {}
     401              : 
     402              :   /* opt_pass methods: */
     403      1515908 :   bool gate (function *) final override
     404              :     {
     405      1515908 :       return true;
     406              :     }
     407              : 
     408              :   unsigned int execute (function *fun) final override;
     409              : }; // class pass_gimple_isel
     410              : 
     411              : 
     412              : 
     413              : /* Convert
     414              :    _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
     415              :    _7 = ~_1;
     416              :    _5 = (_Bool) _7;
     417              :    to
     418              :    _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
     419              :    _8 = _1 & 1;
     420              :    _5 = _8 == 0;
     421              :    and convert
     422              :    _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
     423              :    _7 = ~_1;
     424              :    _4 = (_Bool) _7;
     425              :    to
     426              :    _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
     427              :    _8 = _1 & 1;
     428              :    _4 = (_Bool) _8;
     429              : 
     430              :    USE_STMT is the gimplt statement which uses the return value of
     431              :    __atomic_fetch_or_*.  LHS is the return value of __atomic_fetch_or_*.
     432              :    MASK is the mask passed to __atomic_fetch_or_*.
     433              :  */
     434              : 
     435              : static gimple *
     436           14 : convert_atomic_bit_not (enum internal_fn fn, gimple *use_stmt,
     437              :                         tree lhs, tree mask)
     438              : {
     439           14 :   tree and_mask;
     440           14 :   if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
     441              :     {
     442              :       /* MASK must be ~1.  */
     443            8 :       if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs),
     444              :                                            ~HOST_WIDE_INT_1), mask, 0))
     445              :         return nullptr;
     446            8 :       and_mask = build_int_cst (TREE_TYPE (lhs), 1);
     447              :     }
     448              :   else
     449              :     {
     450              :       /* MASK must be 1.  */
     451            6 :       if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs), 1), mask, 0))
     452              :         return nullptr;
     453              :       and_mask = mask;
     454              :     }
     455              : 
     456           14 :   tree use_lhs = gimple_assign_lhs (use_stmt);
     457              : 
     458           14 :   use_operand_p use_p;
     459           14 :   gimple *use_not_stmt;
     460              : 
     461           14 :   if (!single_imm_use (use_lhs, &use_p, &use_not_stmt)
     462           14 :       || !is_gimple_assign (use_not_stmt))
     463              :     return nullptr;
     464              : 
     465           14 :   if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_not_stmt)))
     466              :     return nullptr;
     467              : 
     468           14 :   tree use_not_lhs = gimple_assign_lhs (use_not_stmt);
     469           14 :   if (TREE_CODE (TREE_TYPE (use_not_lhs)) != BOOLEAN_TYPE)
     470              :     return nullptr;
     471              : 
     472           14 :   gimple_stmt_iterator gsi;
     473           14 :   tree var = make_ssa_name (TREE_TYPE (lhs));
     474              :   /* use_stmt need to be removed after use_nop_stmt,
     475              :      so use_lhs can be released.  */
     476           14 :   gimple *use_stmt_removal = use_stmt;
     477           14 :   use_stmt = gimple_build_assign (var, BIT_AND_EXPR, lhs, and_mask);
     478           14 :   gsi = gsi_for_stmt (use_not_stmt);
     479           14 :   gsi_insert_before (&gsi, use_stmt, GSI_NEW_STMT);
     480           14 :   lhs = gimple_assign_lhs (use_not_stmt);
     481           14 :   gimple *g = gimple_build_assign (lhs, EQ_EXPR, var,
     482           14 :                                    build_zero_cst (TREE_TYPE (mask)));
     483           14 :   gsi_insert_after (&gsi, g, GSI_NEW_STMT);
     484           14 :   gsi = gsi_for_stmt (use_not_stmt);
     485           14 :   gsi_remove (&gsi, true);
     486           14 :   gsi = gsi_for_stmt (use_stmt_removal);
     487           14 :   gsi_remove (&gsi, true);
     488           14 :   return use_stmt;
     489              : }
     490              : 
     491              : /* Optimize
     492              :      mask_2 = 1 << cnt_1;
     493              :      _4 = __atomic_fetch_or_* (ptr_6, mask_2, _3);
     494              :      _5 = _4 & mask_2;
     495              :    to
     496              :      _4 = .ATOMIC_BIT_TEST_AND_SET (ptr_6, cnt_1, 0, _3);
     497              :      _5 = _4;
     498              :    If _5 is only used in _5 != 0 or _5 == 0 comparisons, 1
     499              :    is passed instead of 0, and the builtin just returns a zero
     500              :    or 1 value instead of the actual bit.
     501              :    Similarly for __sync_fetch_and_or_* (without the ", _3" part
     502              :    in there), and/or if mask_2 is a power of 2 constant.
     503              :    Similarly for xor instead of or, use ATOMIC_BIT_TEST_AND_COMPLEMENT
     504              :    in that case.  And similarly for and instead of or, except that
     505              :    the second argument to the builtin needs to be one's complement
     506              :    of the mask instead of mask.  */
     507              : 
     508              : static bool
     509         4651 : optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip,
     510              :                               enum internal_fn fn, bool has_model_arg,
     511              :                               bool after)
     512              : {
     513         4651 :   gimple *call = gsi_stmt (*gsip);
     514         4651 :   tree lhs = gimple_call_lhs (call);
     515         4651 :   use_operand_p use_p;
     516         4651 :   gimple *use_stmt;
     517         4651 :   tree mask;
     518         4651 :   optab optab;
     519              : 
     520         4651 :   if (!flag_inline_atomics
     521         4651 :       || optimize_debug
     522         4651 :       || !gimple_call_builtin_p (call, BUILT_IN_NORMAL)
     523         4651 :       || !lhs
     524         3012 :       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
     525         3012 :       || !single_imm_use (lhs, &use_p, &use_stmt)
     526         2982 :       || !is_gimple_assign (use_stmt)
     527         6411 :       || !gimple_vdef (call))
     528              :     return false;
     529              : 
     530         1760 :   switch (fn)
     531              :     {
     532              :     case IFN_ATOMIC_BIT_TEST_AND_SET:
     533              :       optab = atomic_bit_test_and_set_optab;
     534              :       break;
     535              :     case IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT:
     536              :       optab = atomic_bit_test_and_complement_optab;
     537              :       break;
     538              :     case IFN_ATOMIC_BIT_TEST_AND_RESET:
     539              :       optab = atomic_bit_test_and_reset_optab;
     540              :       break;
     541              :     default:
     542              :       return false;
     543              :     }
     544              : 
     545         1760 :   tree bit = nullptr;
     546              : 
     547         1760 :   mask = gimple_call_arg (call, 1);
     548         1760 :   tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
     549         1760 :   if (rhs_code != BIT_AND_EXPR)
     550              :     {
     551         1468 :       if (rhs_code != NOP_EXPR && rhs_code != BIT_NOT_EXPR)
     552         1311 :         return false;
     553              : 
     554          897 :       tree use_lhs = gimple_assign_lhs (use_stmt);
     555          897 :       if (TREE_CODE (use_lhs) == SSA_NAME
     556          897 :           && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs))
     557              :         return false;
     558              : 
     559          897 :       tree use_rhs = gimple_assign_rhs1 (use_stmt);
     560          897 :       if (lhs != use_rhs)
     561              :         return false;
     562              : 
     563          897 :       if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
     564              :           == CODE_FOR_nothing)
     565              :         return false;
     566              : 
     567          605 :       gimple *g;
     568          605 :       gimple_stmt_iterator gsi;
     569          605 :       tree var;
     570          605 :       int ibit = -1;
     571              : 
     572          605 :       if (rhs_code == BIT_NOT_EXPR)
     573              :         {
     574           14 :           g = convert_atomic_bit_not (fn, use_stmt, lhs, mask);
     575           14 :           if (!g)
     576              :             return false;
     577           14 :           use_stmt = g;
     578           14 :           ibit = 0;
     579              :         }
     580          591 :       else if (TREE_CODE (TREE_TYPE (use_lhs)) == BOOLEAN_TYPE)
     581              :         {
     582           15 :           tree and_mask;
     583           15 :           if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
     584              :             {
     585              :               /* MASK must be ~1.  */
     586            8 :               if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs),
     587              :                                                    ~HOST_WIDE_INT_1),
     588              :                                     mask, 0))
     589              :                 return false;
     590              : 
     591              :               /* Convert
     592              :                  _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
     593              :                  _4 = (_Bool) _1;
     594              :                  to
     595              :                  _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
     596              :                  _5 = _1 & 1;
     597              :                  _4 = (_Bool) _5;
     598              :                */
     599            8 :               and_mask = build_int_cst (TREE_TYPE (lhs), 1);
     600              :             }
     601              :           else
     602              :             {
     603            7 :               and_mask = build_int_cst (TREE_TYPE (lhs), 1);
     604            7 :               if (!operand_equal_p (and_mask, mask, 0))
     605              :                 return false;
     606              : 
     607              :               /* Convert
     608              :                  _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
     609              :                  _4 = (_Bool) _1;
     610              :                  to
     611              :                  _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
     612              :                  _5 = _1 & 1;
     613              :                  _4 = (_Bool) _5;
     614              :                */
     615              :             }
     616           15 :           var = make_ssa_name (TREE_TYPE (use_rhs));
     617           15 :           replace_uses_by (use_rhs, var);
     618           15 :           g = gimple_build_assign (var, BIT_AND_EXPR, use_rhs,
     619              :                                    and_mask);
     620           15 :           gsi = gsi_for_stmt (use_stmt);
     621           15 :           gsi_insert_before (&gsi, g, GSI_NEW_STMT);
     622           15 :           use_stmt = g;
     623           15 :           ibit = 0;
     624              :         }
     625          576 :       else if (TYPE_PRECISION (TREE_TYPE (use_lhs))
     626          576 :                <= TYPE_PRECISION (TREE_TYPE (use_rhs)))
     627              :         {
     628          574 :           gimple *use_nop_stmt;
     629          574 :           if (!single_imm_use (use_lhs, &use_p, &use_nop_stmt)
     630          574 :               || (!is_gimple_assign (use_nop_stmt)
     631           93 :                   && gimple_code (use_nop_stmt) != GIMPLE_COND))
     632          446 :             return false;
     633              :           /* Handle both
     634              :              _4 = _5 < 0;
     635              :              and
     636              :              if (_5 < 0)
     637              :            */
     638          490 :           tree use_nop_lhs = nullptr;
     639          490 :           rhs_code = ERROR_MARK;
     640          490 :           if (is_gimple_assign (use_nop_stmt))
     641              :             {
     642          481 :               use_nop_lhs = gimple_assign_lhs (use_nop_stmt);
     643          481 :               rhs_code = gimple_assign_rhs_code (use_nop_stmt);
     644              :             }
     645          490 :           if (!use_nop_lhs || rhs_code != BIT_AND_EXPR)
     646              :             {
     647              :               /* Also handle
     648              :                  if (_5 < 0)
     649              :                */
     650          396 :               if (use_nop_lhs
     651          387 :                   && TREE_CODE (use_nop_lhs) == SSA_NAME
     652          447 :                   && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_nop_lhs))
     653              :                 return false;
     654          396 :               if (use_nop_lhs && rhs_code == BIT_NOT_EXPR)
     655              :                 {
     656              :                   /* Handle
     657              :                      _7 = ~_2;
     658              :                    */
     659            0 :                   g = convert_atomic_bit_not (fn, use_nop_stmt, lhs,
     660              :                                               mask);
     661            0 :                   if (!g)
     662              :                     return false;
     663              :                   /* Convert
     664              :                      _1 = __atomic_fetch_or_4 (ptr_6, 1, _3);
     665              :                      _2 = (int) _1;
     666              :                      _7 = ~_2;
     667              :                      _5 = (_Bool) _7;
     668              :                      to
     669              :                      _1 = __atomic_fetch_or_4 (ptr_6, ~1, _3);
     670              :                      _8 = _1 & 1;
     671              :                      _5 = _8 == 0;
     672              :                      and convert
     673              :                      _1 = __atomic_fetch_and_4 (ptr_6, ~1, _3);
     674              :                      _2 = (int) _1;
     675              :                      _7 = ~_2;
     676              :                      _5 = (_Bool) _7;
     677              :                      to
     678              :                      _1 = __atomic_fetch_and_4 (ptr_6, 1, _3);
     679              :                      _8 = _1 & 1;
     680              :                      _5 = _8 == 0;
     681              :                    */
     682            0 :                   gsi = gsi_for_stmt (use_stmt);
     683            0 :                   gsi_remove (&gsi, true);
     684            0 :                   use_stmt = g;
     685            0 :                   ibit = 0;
     686              :                 }
     687              :               else
     688              :                 {
     689          396 :                   tree cmp_rhs1, cmp_rhs2;
     690          396 :                   if (use_nop_lhs)
     691              :                     {
     692              :                       /* Handle
     693              :                          _4 = _5 < 0;
     694              :                        */
     695          387 :                       if (TREE_CODE (TREE_TYPE (use_nop_lhs))
     696              :                           != BOOLEAN_TYPE)
     697          446 :                         return false;
     698           51 :                       cmp_rhs1 = gimple_assign_rhs1 (use_nop_stmt);
     699           51 :                       cmp_rhs2 = gimple_assign_rhs2 (use_nop_stmt);
     700              :                     }
     701              :                   else
     702              :                     {
     703              :                       /* Handle
     704              :                          if (_5 < 0)
     705              :                        */
     706            9 :                       rhs_code = gimple_cond_code (use_nop_stmt);
     707            9 :                       cmp_rhs1 = gimple_cond_lhs (use_nop_stmt);
     708            9 :                       cmp_rhs2 = gimple_cond_rhs (use_nop_stmt);
     709              :                     }
     710           60 :                   if (rhs_code != GE_EXPR && rhs_code != LT_EXPR)
     711              :                     return false;
     712           48 :                   if (use_lhs != cmp_rhs1)
     713              :                     return false;
     714           48 :                   if (!integer_zerop (cmp_rhs2))
     715              :                     return false;
     716              : 
     717           48 :                   tree and_mask;
     718              : 
     719           48 :                   unsigned HOST_WIDE_INT bytes
     720           48 :                     = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (use_rhs)));
     721           48 :                   ibit = bytes * BITS_PER_UNIT - 1;
     722           48 :                   unsigned HOST_WIDE_INT highest
     723           48 :                     = HOST_WIDE_INT_1U << ibit;
     724              : 
     725           48 :                   if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
     726              :                     {
     727              :                       /* Get the signed maximum of the USE_RHS type.  */
     728           19 :                       and_mask = build_int_cst (TREE_TYPE (use_rhs),
     729           19 :                                                 highest - 1);
     730           19 :                       if (!operand_equal_p (and_mask, mask, 0))
     731              :                         return false;
     732              : 
     733              :                       /* Convert
     734              :                          _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
     735              :                          _5 = (signed int) _1;
     736              :                          _4 = _5 < 0 or _5 >= 0;
     737              :                          to
     738              :                          _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
     739              :                          _6 = _1 & 0x80000000;
     740              :                          _4 = _6 != 0 or _6 == 0;
     741              :                          and convert
     742              :                          _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
     743              :                          _5 = (signed int) _1;
     744              :                          if (_5 < 0 or _5 >= 0)
     745              :                          to
     746              :                          _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
     747              :                          _6 = _1 & 0x80000000;
     748              :                          if (_6 != 0 or _6 == 0)
     749              :                        */
     750           19 :                       and_mask = build_int_cst (TREE_TYPE (use_rhs),
     751           19 :                                                 highest);
     752              :                     }
     753              :                   else
     754              :                     {
     755              :                       /* Get the signed minimum of the USE_RHS type.  */
     756           29 :                       and_mask = build_int_cst (TREE_TYPE (use_rhs),
     757           29 :                                                 highest);
     758           29 :                       if (!operand_equal_p (and_mask, mask, 0))
     759              :                         return false;
     760              : 
     761              :                       /* Convert
     762              :                          _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
     763              :                          _5 = (signed int) _1;
     764              :                          _4 = _5 < 0 or _5 >= 0;
     765              :                          to
     766              :                          _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
     767              :                          _6 = _1 & 0x80000000;
     768              :                          _4 = _6 != 0 or _6 == 0;
     769              :                          and convert
     770              :                          _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
     771              :                          _5 = (signed int) _1;
     772              :                          if (_5 < 0 or _5 >= 0)
     773              :                          to
     774              :                          _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
     775              :                          _6 = _1 & 0x80000000;
     776              :                          if (_6 != 0 or _6 == 0)
     777              :                        */
     778              :                     }
     779           36 :                   var = make_ssa_name (TREE_TYPE (use_rhs));
     780           36 :                   gimple* use_stmt_removal = use_stmt;
     781           36 :                   g = gimple_build_assign (var, BIT_AND_EXPR, use_rhs,
     782              :                                            and_mask);
     783           36 :                   gsi = gsi_for_stmt (use_nop_stmt);
     784           36 :                   gsi_insert_before (&gsi, g, GSI_NEW_STMT);
     785           36 :                   use_stmt = g;
     786           36 :                   rhs_code = rhs_code == GE_EXPR ? EQ_EXPR : NE_EXPR;
     787           36 :                   tree const_zero = build_zero_cst (TREE_TYPE (use_rhs));
     788           36 :                   if (use_nop_lhs)
     789           27 :                     g = gimple_build_assign (use_nop_lhs, rhs_code,
     790              :                                              var, const_zero);
     791              :                   else
     792            9 :                     g = gimple_build_cond (rhs_code, var, const_zero,
     793              :                                            nullptr, nullptr);
     794           36 :                   gsi_insert_after (&gsi, g, GSI_NEW_STMT);
     795           36 :                   gsi = gsi_for_stmt (use_nop_stmt);
     796           36 :                   gsi_remove (&gsi, true);
     797           36 :                   gsi = gsi_for_stmt (use_stmt_removal);
     798           36 :                   gsi_remove (&gsi, true);
     799              :                 }
     800              :             }
     801              :           else
     802              :             {
     803           94 :               tree match_op[3];
     804           94 :               gimple *g;
     805           94 :               if (!gimple_nop_atomic_bit_test_and_p (use_nop_lhs,
     806              :                                                      &match_op[0], NULL)
     807           92 :                   || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (match_op[2])
     808           92 :                   || !single_imm_use (match_op[2], &use_p, &g)
     809          186 :                   || !is_gimple_assign (g))
     810            2 :                 return false;
     811           92 :               mask = match_op[0];
     812           92 :               if (TREE_CODE (match_op[1]) == INTEGER_CST)
     813              :                 {
     814           48 :                   ibit = tree_log2 (match_op[1]);
     815           48 :                   gcc_assert (ibit >= 0);
     816              :                 }
     817              :               else
     818              :                 {
     819           44 :                   g = SSA_NAME_DEF_STMT (match_op[1]);
     820           44 :                   gcc_assert (is_gimple_assign (g));
     821           44 :                   bit = gimple_assign_rhs2 (g);
     822              :                 }
     823              :               /* Convert
     824              :                  _1 = __atomic_fetch_or_4 (ptr_6, mask, _3);
     825              :                  _2 = (int) _1;
     826              :                  _5 = _2 & mask;
     827              :                  to
     828              :                  _1 = __atomic_fetch_or_4 (ptr_6, mask, _3);
     829              :                  _6 = _1 & mask;
     830              :                  _5 = (int) _6;
     831              :                  and convert
     832              :                  _1 = ~mask_7;
     833              :                  _2 = (unsigned int) _1;
     834              :                  _3 = __atomic_fetch_and_4 (ptr_6, _2, 0);
     835              :                  _4 = (int) _3;
     836              :                  _5 = _4 & mask_7;
     837              :                  to
     838              :                  _1 = __atomic_fetch_and_* (ptr_6, ~mask_7, _3);
     839              :                  _12 = _3 & mask_7;
     840              :                  _5 = (int) _12;
     841              : 
     842              :                  and Convert
     843              :                  _1 = __atomic_fetch_and_4 (ptr_6, ~mask, _3);
     844              :                  _2 = (short int) _1;
     845              :                  _5 = _2 & mask;
     846              :                  to
     847              :                  _1 = __atomic_fetch_and_4 (ptr_6, ~mask, _3);
     848              :                  _8 = _1 & mask;
     849              :                  _5 = (short int) _8;
     850              :               */
     851           92 :               gimple_seq stmts = NULL;
     852           92 :               match_op[1] = gimple_convert (&stmts,
     853           92 :                                             TREE_TYPE (use_rhs),
     854              :                                             match_op[1]);
     855           92 :               var = gimple_build (&stmts, BIT_AND_EXPR,
     856           92 :                                   TREE_TYPE (use_rhs), use_rhs, match_op[1]);
     857           92 :               gsi = gsi_for_stmt (use_stmt);
     858           92 :               gsi_remove (&gsi, true);
     859           92 :               release_defs (use_stmt);
     860           92 :               use_stmt = gimple_seq_last_stmt (stmts);
     861           92 :               gsi = gsi_for_stmt (use_nop_stmt);
     862           92 :               gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
     863           92 :               gimple_assign_set_rhs_with_ops (&gsi, CONVERT_EXPR, var);
     864           92 :               update_stmt (use_nop_stmt);
     865              :             }
     866              :         }
     867              :       else
     868              :         return false;
     869              : 
     870          157 :       if (!bit)
     871              :         {
     872          113 :           if (ibit < 0)
     873            0 :             gcc_unreachable ();
     874          113 :           bit = build_int_cst (TREE_TYPE (lhs), ibit);
     875              :         }
     876              :     }
     877          292 :   else if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
     878              :            == CODE_FOR_nothing)
     879              :     return false;
     880              : 
     881          443 :   tree use_lhs = gimple_assign_lhs (use_stmt);
     882          443 :   if (!use_lhs)
     883              :     return false;
     884              : 
     885          443 :   if (!bit)
     886              :     {
     887          286 :       if (TREE_CODE (mask) == INTEGER_CST)
     888              :         {
     889          222 :           if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
     890           62 :             mask = const_unop (BIT_NOT_EXPR, TREE_TYPE (mask), mask);
     891          222 :           mask = fold_convert (TREE_TYPE (lhs), mask);
     892          222 :           int ibit = tree_log2 (mask);
     893          222 :           if (ibit < 0)
     894           16 :             return false;
     895          220 :           bit = build_int_cst (TREE_TYPE (lhs), ibit);
     896              :         }
     897           64 :       else if (TREE_CODE (mask) == SSA_NAME)
     898              :         {
     899           64 :           gimple *g = SSA_NAME_DEF_STMT (mask);
     900           64 :           tree match_op;
     901           64 :           if (gimple_nop_convert (mask, &match_op, NULL))
     902              :             {
     903            3 :               mask = match_op;
     904            3 :               if (TREE_CODE (mask) != SSA_NAME)
     905            7 :                 return false;
     906            3 :               g = SSA_NAME_DEF_STMT (mask);
     907              :             }
     908           64 :           if (!is_gimple_assign (g))
     909              :             return false;
     910              : 
     911           62 :           if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
     912              :             {
     913           20 :               if (gimple_assign_rhs_code (g) != BIT_NOT_EXPR)
     914              :                 return false;
     915           20 :               mask = gimple_assign_rhs1 (g);
     916           20 :               if (TREE_CODE (mask) != SSA_NAME)
     917              :                 return false;
     918           20 :               g = SSA_NAME_DEF_STMT (mask);
     919              :             }
     920              : 
     921           62 :           if (!is_gimple_assign (g)
     922           57 :               || gimple_assign_rhs_code (g) != LSHIFT_EXPR
     923          119 :               || !integer_onep (gimple_assign_rhs1 (g)))
     924              :             return false;
     925           57 :           bit = gimple_assign_rhs2 (g);
     926              :         }
     927              :       else
     928              :         return false;
     929              : 
     930          277 :       tree cmp_mask;
     931          277 :       if (gimple_assign_rhs1 (use_stmt) == lhs)
     932          241 :         cmp_mask = gimple_assign_rhs2 (use_stmt);
     933              :       else
     934              :         cmp_mask = gimple_assign_rhs1 (use_stmt);
     935              : 
     936          277 :       tree match_op;
     937          277 :       if (gimple_nop_convert (cmp_mask, &match_op, NULL))
     938            1 :         cmp_mask = match_op;
     939              : 
     940          277 :       if (!operand_equal_p (cmp_mask, mask, 0))
     941              :         return false;
     942              :     }
     943              : 
     944          427 :   bool use_bool = true;
     945          427 :   bool has_debug_uses = false;
     946          427 :   imm_use_iterator iter;
     947          427 :   gimple *g;
     948              : 
     949          427 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs))
     950            0 :     use_bool = false;
     951          629 :   FOR_EACH_IMM_USE_STMT (g, iter, use_lhs)
     952              :     {
     953          428 :       enum tree_code code = ERROR_MARK;
     954          428 :       tree op0 = NULL_TREE, op1 = NULL_TREE;
     955          428 :       if (is_gimple_debug (g))
     956              :         {
     957            1 :           has_debug_uses = true;
     958            1 :           continue;
     959              :         }
     960          427 :       else if (is_gimple_assign (g))
     961          385 :         switch (gimple_assign_rhs_code (g))
     962              :           {
     963            0 :           case COND_EXPR:
     964            0 :             op1 = gimple_assign_rhs1 (g);
     965            0 :             code = TREE_CODE (op1);
     966            0 :             if (TREE_CODE_CLASS (code) != tcc_comparison)
     967              :               break;
     968            0 :             op0 = TREE_OPERAND (op1, 0);
     969            0 :             op1 = TREE_OPERAND (op1, 1);
     970            0 :             break;
     971          173 :           case EQ_EXPR:
     972          173 :           case NE_EXPR:
     973          173 :             code = gimple_assign_rhs_code (g);
     974          173 :             op0 = gimple_assign_rhs1 (g);
     975          173 :             op1 = gimple_assign_rhs2 (g);
     976          173 :             break;
     977              :           default:
     978              :             break;
     979              :           }
     980           42 :       else if (gimple_code (g) == GIMPLE_COND)
     981              :         {
     982           28 :           code = gimple_cond_code (g);
     983           28 :           op0 = gimple_cond_lhs (g);
     984           28 :           op1 = gimple_cond_rhs (g);
     985              :         }
     986              : 
     987          201 :       if ((code == EQ_EXPR || code == NE_EXPR)
     988          201 :           && op0 == use_lhs
     989          402 :           && integer_zerop (op1))
     990              :         {
     991          201 :           use_operand_p use_p;
     992          201 :           int n = 0;
     993          402 :           FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
     994          201 :             n++;
     995          201 :           if (n == 1)
     996          201 :             continue;
     997              :         }
     998              : 
     999              :       use_bool = false;
    1000              :       break;
    1001          427 :     }
    1002              : 
    1003          427 :   tree new_lhs = make_ssa_name (TREE_TYPE (lhs));
    1004          427 :   tree flag = build_int_cst (TREE_TYPE (lhs), use_bool);
    1005          427 :   if (has_model_arg)
    1006          296 :     g = gimple_build_call_internal (fn, 5, gimple_call_arg (call, 0),
    1007              :                                     bit, flag, gimple_call_arg (call, 2),
    1008              :                                     gimple_call_fn (call));
    1009              :   else
    1010          131 :     g = gimple_build_call_internal (fn, 4, gimple_call_arg (call, 0),
    1011              :                                     bit, flag, gimple_call_fn (call));
    1012          427 :   gimple_call_set_lhs (g, new_lhs);
    1013          427 :   gimple_set_location (g, gimple_location (call));
    1014          427 :   gimple_move_vops (g, call);
    1015          427 :   bool throws = stmt_can_throw_internal (cfun, call);
    1016          427 :   gimple_call_set_nothrow (as_a <gcall *> (g),
    1017          427 :                            gimple_call_nothrow_p (as_a <gcall *> (call)));
    1018          427 :   gimple_stmt_iterator gsi = *gsip;
    1019          427 :   gsi_insert_after (&gsi, g, GSI_NEW_STMT);
    1020          427 :   edge e = NULL;
    1021          427 :   if (throws)
    1022              :     {
    1023           75 :       maybe_clean_or_replace_eh_stmt (call, g);
    1024           75 :       if (after || (use_bool && has_debug_uses))
    1025            9 :         e = find_fallthru_edge (gsi_bb (gsi)->succs);
    1026              :     }
    1027          427 :   if (after)
    1028              :     {
    1029              :       /* The internal function returns the value of the specified bit
    1030              :          before the atomic operation.  If we are interested in the value
    1031              :          of the specified bit after the atomic operation (makes only sense
    1032              :          for xor, otherwise the bit content is compile time known),
    1033              :          we need to invert the bit.  */
    1034           55 :       tree mask_convert = mask;
    1035           55 :       gimple_seq stmts = NULL;
    1036           55 :       if (!use_bool)
    1037           43 :         mask_convert = gimple_convert (&stmts, TREE_TYPE (lhs), mask);
    1038           55 :       new_lhs = gimple_build (&stmts, BIT_XOR_EXPR, TREE_TYPE (lhs), new_lhs,
    1039           12 :                               use_bool ? build_int_cst (TREE_TYPE (lhs), 1)
    1040              :                                        : mask_convert);
    1041           55 :       if (throws)
    1042              :         {
    1043            9 :           gsi_insert_seq_on_edge_immediate (e, stmts);
    1044           18 :           gsi = gsi_for_stmt (gimple_seq_last (stmts));
    1045              :         }
    1046              :       else
    1047           46 :         gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT);
    1048              :     }
    1049          427 :   if (use_bool && has_debug_uses)
    1050              :     {
    1051            1 :       tree temp = NULL_TREE;
    1052            1 :       if (!throws || after || single_pred_p (e->dest))
    1053              :         {
    1054            1 :           temp = build_debug_expr_decl (TREE_TYPE (lhs));
    1055            1 :           tree t = build2 (LSHIFT_EXPR, TREE_TYPE (lhs), new_lhs, bit);
    1056            1 :           g = gimple_build_debug_bind (temp, t, g);
    1057            1 :           if (throws && !after)
    1058              :             {
    1059            0 :               gsi = gsi_after_labels (e->dest);
    1060            0 :               gsi_insert_before (&gsi, g, GSI_SAME_STMT);
    1061              :             }
    1062              :           else
    1063            1 :             gsi_insert_after (&gsi, g, GSI_NEW_STMT);
    1064              :         }
    1065            3 :       FOR_EACH_IMM_USE_STMT (g, iter, use_lhs)
    1066            2 :         if (is_gimple_debug (g))
    1067              :           {
    1068            1 :             use_operand_p use_p;
    1069            1 :             if (temp == NULL_TREE)
    1070            0 :               gimple_debug_bind_reset_value (g);
    1071              :             else
    1072            2 :               FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
    1073            1 :                 SET_USE (use_p, temp);
    1074            1 :             update_stmt (g);
    1075            1 :           }
    1076              :     }
    1077          427 :   SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_lhs)
    1078          427 :     = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs);
    1079          427 :   replace_uses_by (use_lhs, new_lhs);
    1080          427 :   gsi = gsi_for_stmt (use_stmt);
    1081          427 :   gsi_remove (&gsi, true);
    1082          427 :   release_defs (use_stmt);
    1083          427 :   gsi_remove (gsip, true);
    1084          427 :   release_ssa_name (lhs);
    1085          427 :   return true;
    1086              : }
    1087              : 
    1088              : /* Optimize
    1089              :      _4 = __atomic_add_fetch_* (ptr_6, arg_2, _3);
    1090              :      _5 = _4 == 0;
    1091              :    to
    1092              :      _4 = .ATOMIC_ADD_FETCH_CMP_0 (EQ_EXPR, ptr_6, arg_2, _3);
    1093              :      _5 = _4;
    1094              :    Similarly for __sync_add_and_fetch_* (without the ", _3" part
    1095              :    in there).  */
    1096              : 
    1097              : static bool
    1098         8857 : optimize_atomic_op_fetch_cmp_0 (gimple_stmt_iterator *gsip,
    1099              :                                 enum internal_fn fn, bool has_model_arg)
    1100              : {
    1101         8857 :   gimple *call = gsi_stmt (*gsip);
    1102         8857 :   tree lhs = gimple_call_lhs (call);
    1103         8857 :   use_operand_p use_p;
    1104         8857 :   gimple *use_stmt;
    1105              : 
    1106         8857 :   if (!flag_inline_atomics
    1107         8857 :       || !gimple_call_builtin_p (call, BUILT_IN_NORMAL)
    1108         8857 :       || !lhs
    1109         6332 :       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
    1110         6332 :       || !single_imm_use (lhs, &use_p, &use_stmt)
    1111        15015 :       || !gimple_vdef (call))
    1112              :     return false;
    1113              : 
    1114         6158 :   optab optab;
    1115         6158 :   switch (fn)
    1116              :     {
    1117              :     case IFN_ATOMIC_ADD_FETCH_CMP_0:
    1118              :       optab = atomic_add_fetch_cmp_0_optab;
    1119              :       break;
    1120              :     case IFN_ATOMIC_SUB_FETCH_CMP_0:
    1121              :       optab = atomic_sub_fetch_cmp_0_optab;
    1122              :       break;
    1123              :     case IFN_ATOMIC_AND_FETCH_CMP_0:
    1124              :       optab = atomic_and_fetch_cmp_0_optab;
    1125              :       break;
    1126              :     case IFN_ATOMIC_OR_FETCH_CMP_0:
    1127              :       optab = atomic_or_fetch_cmp_0_optab;
    1128              :       break;
    1129              :     case IFN_ATOMIC_XOR_FETCH_CMP_0:
    1130              :       optab = atomic_xor_fetch_cmp_0_optab;
    1131              :       break;
    1132              :     default:
    1133              :       return false;
    1134              :     }
    1135              : 
    1136         6158 :   if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
    1137              :       == CODE_FOR_nothing)
    1138              :     return false;
    1139              : 
    1140         6119 :   tree use_lhs = lhs;
    1141         6119 :   if (gimple_assign_cast_p (use_stmt))
    1142              :     {
    1143          965 :       use_lhs = gimple_assign_lhs (use_stmt);
    1144          965 :       if (!tree_nop_conversion_p (TREE_TYPE (use_lhs), TREE_TYPE (lhs))
    1145          943 :           || (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
    1146           91 :               && !POINTER_TYPE_P (TREE_TYPE (use_lhs)))
    1147          943 :           || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs)
    1148         1908 :           || !single_imm_use (use_lhs, &use_p, &use_stmt))
    1149              :         return false;
    1150              :     }
    1151         6028 :   enum tree_code code = ERROR_MARK;
    1152         6028 :   tree op0 = NULL_TREE, op1 = NULL_TREE;
    1153         6028 :   if (is_gimple_assign (use_stmt))
    1154         1286 :     switch (gimple_assign_rhs_code (use_stmt))
    1155              :       {
    1156            0 :       case COND_EXPR:
    1157            0 :         op1 = gimple_assign_rhs1 (use_stmt);
    1158            0 :         code = TREE_CODE (op1);
    1159            0 :         if (TREE_CODE_CLASS (code) == tcc_comparison)
    1160              :           {
    1161            0 :             op0 = TREE_OPERAND (op1, 0);
    1162            0 :             op1 = TREE_OPERAND (op1, 1);
    1163              :           }
    1164              :         break;
    1165         1286 :       default:
    1166         1286 :         code = gimple_assign_rhs_code (use_stmt);
    1167         1286 :         if (TREE_CODE_CLASS (code) == tcc_comparison)
    1168              :           {
    1169          839 :             op0 = gimple_assign_rhs1 (use_stmt);
    1170          839 :             op1 = gimple_assign_rhs2 (use_stmt);
    1171              :           }
    1172              :         break;
    1173              :       }
    1174         4742 :   else if (gimple_code (use_stmt) == GIMPLE_COND)
    1175              :     {
    1176         4227 :       code = gimple_cond_code (use_stmt);
    1177         4227 :       op0 = gimple_cond_lhs (use_stmt);
    1178         4227 :       op1 = gimple_cond_rhs (use_stmt);
    1179              :     }
    1180              : 
    1181         5513 :   switch (code)
    1182              :     {
    1183          243 :     case LT_EXPR:
    1184          243 :     case LE_EXPR:
    1185          243 :     case GT_EXPR:
    1186          243 :     case GE_EXPR:
    1187          486 :       if (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
    1188          243 :           || TREE_CODE (TREE_TYPE (use_lhs)) == BOOLEAN_TYPE
    1189          486 :           || TYPE_UNSIGNED (TREE_TYPE (use_lhs)))
    1190              :         return false;
    1191              :       /* FALLTHRU */
    1192         5066 :     case EQ_EXPR:
    1193         5066 :     case NE_EXPR:
    1194         5066 :       if (op0 == use_lhs && integer_zerop (op1))
    1195              :         break;
    1196              :       return false;
    1197              :     default:
    1198              :       return false;
    1199              :     }
    1200              : 
    1201         2148 :   int encoded;
    1202         2148 :   switch (code)
    1203              :     {
    1204              :     /* Use special encoding of the operation.  We want to also
    1205              :        encode the mode in the first argument and for neither EQ_EXPR
    1206              :        etc. nor EQ etc. we can rely it will fit into QImode.  */
    1207              :     case EQ_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_EQ; break;
    1208              :     case NE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_NE; break;
    1209              :     case LT_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_LT; break;
    1210              :     case LE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_LE; break;
    1211              :     case GT_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_GT; break;
    1212              :     case GE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_GE; break;
    1213              :     default: gcc_unreachable ();
    1214              :     }
    1215              : 
    1216         2148 :   tree new_lhs = make_ssa_name (boolean_type_node);
    1217         2148 :   gimple *g;
    1218         2148 :   tree flag = build_int_cst (TREE_TYPE (lhs), encoded);
    1219         2148 :   if (has_model_arg)
    1220         1740 :     g = gimple_build_call_internal (fn, 5, flag,
    1221              :                                     gimple_call_arg (call, 0),
    1222              :                                     gimple_call_arg (call, 1),
    1223              :                                     gimple_call_arg (call, 2),
    1224              :                                     gimple_call_fn (call));
    1225              :   else
    1226          408 :     g = gimple_build_call_internal (fn, 4, flag,
    1227              :                                     gimple_call_arg (call, 0),
    1228              :                                     gimple_call_arg (call, 1),
    1229              :                                     gimple_call_fn (call));
    1230         2148 :   gimple_call_set_lhs (g, new_lhs);
    1231         2148 :   gimple_set_location (g, gimple_location (call));
    1232         2148 :   gimple_move_vops (g, call);
    1233         2148 :   bool throws = stmt_can_throw_internal (cfun, call);
    1234         2148 :   gimple_call_set_nothrow (as_a <gcall *> (g),
    1235         2148 :                            gimple_call_nothrow_p (as_a <gcall *> (call)));
    1236         2148 :   gimple_stmt_iterator gsi = *gsip;
    1237         2148 :   gsi_insert_after (&gsi, g, GSI_SAME_STMT);
    1238         2148 :   if (throws)
    1239            0 :     maybe_clean_or_replace_eh_stmt (call, g);
    1240         2148 :   if (is_gimple_assign (use_stmt))
    1241          816 :     switch (gimple_assign_rhs_code (use_stmt))
    1242              :       {
    1243            0 :       case COND_EXPR:
    1244            0 :         gimple_assign_set_rhs1 (use_stmt, new_lhs);
    1245            0 :         break;
    1246          816 :       default:
    1247          816 :         gsi = gsi_for_stmt (use_stmt);
    1248          816 :         if (tree ulhs = gimple_assign_lhs (use_stmt))
    1249          816 :           if (useless_type_conversion_p (TREE_TYPE (ulhs),
    1250              :                                          boolean_type_node))
    1251              :             {
    1252          816 :               gimple_assign_set_rhs_with_ops (&gsi, SSA_NAME, new_lhs);
    1253          816 :               break;
    1254              :             }
    1255            0 :         gimple_assign_set_rhs_with_ops (&gsi, NOP_EXPR, new_lhs);
    1256            0 :         break;
    1257              :       }
    1258         1332 :   else if (gimple_code (use_stmt) == GIMPLE_COND)
    1259              :     {
    1260         1332 :       gcond *use_cond = as_a <gcond *> (use_stmt);
    1261         1332 :       gimple_cond_set_code (use_cond, NE_EXPR);
    1262         1332 :       gimple_cond_set_lhs (use_cond, new_lhs);
    1263         1332 :       gimple_cond_set_rhs (use_cond, boolean_false_node);
    1264              :     }
    1265              : 
    1266         2148 :   update_stmt (use_stmt);
    1267         2148 :   if (use_lhs != lhs)
    1268              :     {
    1269          234 :       gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (use_lhs));
    1270          234 :       gsi_remove (&gsi, true);
    1271          234 :       release_ssa_name (use_lhs);
    1272              :     }
    1273         2148 :   gsi_remove (gsip, true);
    1274         2148 :   release_ssa_name (lhs);
    1275         2148 :   return true;
    1276              : }
    1277              : 
    1278              : /* Process builtin CALL located at GSI.
    1279              :    Currently it is only fgr atomic functions optimizations from above. */
    1280              : static void
    1281      7073150 : gimple_isel_builtin_call (gcall *call, gimple_stmt_iterator *gsi)
    1282              : {
    1283              :   /* Don't handle these in non optimization mode or optimize debug mode.  */
    1284      7073150 :   if (!optimize || optimize_debug)
    1285              :     return;
    1286              : 
    1287      5497571 :   if (!gimple_call_builtin_p (call, BUILT_IN_NORMAL))
    1288              :     return;
    1289              : 
    1290      1376242 :   tree callee = gimple_call_fndecl (call);
    1291              :   
    1292      1376242 :   switch (DECL_FUNCTION_CODE (callee))
    1293              :     {
    1294              : #define CASE_ATOMIC(NAME)                       \
    1295              :       case BUILT_IN_##NAME##_1: \
    1296              :       case BUILT_IN_##NAME##_2: \
    1297              :       case BUILT_IN_##NAME##_4: \
    1298              :       case BUILT_IN_##NAME##_8: \
    1299              :       case BUILT_IN_##NAME##_16
    1300              : #define CASE_ATOMIC_CMP0(ATOMIC, SYNC)                                  \
    1301              :       CASE_ATOMIC(ATOMIC_##ATOMIC):                                     \
    1302              :         optimize_atomic_op_fetch_cmp_0 (gsi,                            \
    1303              :                                         IFN_ATOMIC_##ATOMIC##_CMP_0,    \
    1304              :                                         true);                          \
    1305              :         break;                                                          \
    1306              :       CASE_ATOMIC(SYNC_##SYNC):                                         \
    1307              :         optimize_atomic_op_fetch_cmp_0 (gsi,                            \
    1308              :                                         IFN_ATOMIC_##ATOMIC##_CMP_0,    \
    1309              :                                         false);                         \
    1310              :       break;
    1311              : 
    1312              : 
    1313         4183 :       CASE_ATOMIC_CMP0(ADD_FETCH, ADD_AND_FETCH)
    1314         2391 :       CASE_ATOMIC_CMP0(SUB_FETCH, SUB_AND_FETCH)
    1315          780 :       CASE_ATOMIC_CMP0(AND_FETCH, AND_AND_FETCH)
    1316          778 :       CASE_ATOMIC_CMP0(OR_FETCH, OR_AND_FETCH)
    1317              : #define CASE_ATOMIC_BIT_TEST_AND(ATOMIC, SYNC, FN, AFTER)               \
    1318              :       CASE_ATOMIC(ATOMIC_##ATOMIC):                                     \
    1319              :         optimize_atomic_bit_test_and (gsi,                              \
    1320              :                                       IFN_ATOMIC_BIT_TEST_AND_##FN,     \
    1321              :                                       true, AFTER);                     \
    1322              :         break;                                                          \
    1323              :       CASE_ATOMIC(SYNC_##SYNC):                                         \
    1324              :         optimize_atomic_bit_test_and (gsi,                              \
    1325              :                                       IFN_ATOMIC_BIT_TEST_AND_##FN,     \
    1326              :                                       false, AFTER);                    \
    1327              :         break;
    1328         1430 :       CASE_ATOMIC_BIT_TEST_AND(FETCH_OR,  FETCH_AND_OR,  SET, false)
    1329         1291 :       CASE_ATOMIC_BIT_TEST_AND(FETCH_XOR, FETCH_AND_XOR, COMPLEMENT, false)
    1330         1150 :       CASE_ATOMIC_BIT_TEST_AND(FETCH_AND, FETCH_AND_AND, RESET, false)
    1331              : 
    1332          580 :       CASE_ATOMIC(ATOMIC_XOR_FETCH):
    1333          580 :         if (optimize_atomic_bit_test_and
    1334          580 :              (gsi, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, true, true))
    1335              :           break;
    1336          542 :         optimize_atomic_op_fetch_cmp_0 (gsi,
    1337              :                                         IFN_ATOMIC_XOR_FETCH_CMP_0,
    1338              :                                         true);
    1339          542 :         break;
    1340          200 :       CASE_ATOMIC(SYNC_XOR_AND_FETCH):
    1341          200 :         if (optimize_atomic_bit_test_and
    1342          200 :               (gsi, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, false, true))
    1343              :           break;
    1344          183 :         optimize_atomic_op_fetch_cmp_0 (gsi,
    1345              :                                         IFN_ATOMIC_XOR_FETCH_CMP_0,
    1346              :                                         false);
    1347          183 :         break;
    1348              : 
    1349           55 :       default:;
    1350              :     }
    1351              : }
    1352              : 
    1353              : /* Iterate all gimple statements and perform pre RTL expansion
    1354              :    GIMPLE massaging to improve instruction selection.  */
    1355              : 
    1356              : unsigned int
    1357      1515903 : pass_gimple_isel::execute (struct function *fun)
    1358              : {
    1359      1515903 :   gimple_stmt_iterator gsi;
    1360      1515903 :   basic_block bb;
    1361      1515903 :   bool cfg_changed = false;
    1362      1515903 :   if (optimize)
    1363      1062676 :     enable_ranger (fun);
    1364              : 
    1365     17475900 :   FOR_EACH_BB_FN (bb, fun)
    1366              :     {
    1367    134415147 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    1368              :         {
    1369              :           /* Give the target first try at replacing the instruction.  */
    1370    102495153 :           cfg_changed |= targetm.instruction_selection (fun, &gsi);
    1371              : 
    1372              :           /* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
    1373              :              calls mapping to supported optabs.  */
    1374    102495153 :           gimple *g = gimple_expand_vec_cond_expr (&gsi);
    1375    102495153 :           if (g != NULL)
    1376              :             {
    1377        22602 :               tree lhs = gimple_assign_lhs (gsi_stmt (gsi));
    1378        22602 :               gimple_set_lhs (g, lhs);
    1379        22602 :               gsi_replace (&gsi, g, false);
    1380              :             }
    1381              : 
    1382              :           /* Recognize .VEC_SET and .VEC_EXTRACT patterns.  */
    1383    102495153 :           cfg_changed |= gimple_expand_vec_set_extract_expr (fun, &gsi);
    1384    102495153 :           if (gsi_end_p (gsi))
    1385              :             break;
    1386              : 
    1387    102495153 :           if (gcall *call = dyn_cast <gcall*>(*gsi))
    1388              :             {
    1389      7073150 :               gimple_isel_builtin_call (call, &gsi);
    1390      7073150 :               continue;
    1391              :             }
    1392     95422003 :           gassign *stmt = dyn_cast <gassign *> (*gsi);
    1393     95422003 :           if (!stmt)
    1394     62664015 :             continue;
    1395              : 
    1396     32757988 :           tree_code code = gimple_assign_rhs_code (stmt);
    1397     32757988 :           if (TREE_CODE_CLASS (code) == tcc_comparison)
    1398       589297 :             maybe_duplicate_comparison (stmt, bb);
    1399              :         }
    1400              :     }
    1401              : 
    1402      1515903 :   if (optimize)
    1403      1062676 :     disable_ranger (fun);
    1404      1515903 :   return cfg_changed ? TODO_cleanup_cfg : 0;
    1405              : }
    1406              : 
    1407              : } // anon namespace
    1408              : 
    1409              : gimple_opt_pass *
    1410       294196 : make_pass_gimple_isel (gcc::context *ctxt)
    1411              : {
    1412       294196 :   return new pass_gimple_isel (ctxt);
    1413              : }
    1414              : 
        

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.