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

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.