LCOV - code coverage report
Current view: top level - gcc - internal-fn.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.0 % 2525 1793
Test Date: 2026-10-17 16:30:31 Functions: 58.8 % 177 104
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Internal functions.
       2              :    Copyright (C) 2011-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it under
       7              : the terms of the GNU General Public License as published by the Free
       8              : Software Foundation; either version 3, or (at your option) any later
       9              : version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #define INCLUDE_MEMORY
      22              : #include "system.h"
      23              : #include "coretypes.h"
      24              : #include "backend.h"
      25              : #include "target.h"
      26              : #include "rtl.h"
      27              : #include "tree.h"
      28              : #include "tree-eh.h"
      29              : #include "gimple.h"
      30              : #include "predict.h"
      31              : #include "stringpool.h"
      32              : #include "tree-vrp.h"
      33              : #include "tree-ssanames.h"
      34              : #include "expmed.h"
      35              : #include "memmodel.h"
      36              : #include "optabs.h"
      37              : #include "emit-rtl.h"
      38              : #include "diagnostic-core.h"
      39              : #include "fold-const.h"
      40              : #include "internal-fn.h"
      41              : #include "stor-layout.h"
      42              : #include "dojump.h"
      43              : #include "expr.h"
      44              : #include "attribs.h"
      45              : #include "asan.h"
      46              : #include "ubsan.h"
      47              : #include "recog.h"
      48              : #include "builtins.h"
      49              : #include "optabs-tree.h"
      50              : #include "gimple-ssa.h"
      51              : #include "tree-phinodes.h"
      52              : #include "ssa-iterators.h"
      53              : #include "explow.h"
      54              : #include "rtl-iter.h"
      55              : #include "gimple-range.h"
      56              : #include "fold-const-call.h"
      57              : #include "tree-ssa-live.h"
      58              : #include "tree-outof-ssa.h"
      59              : #include "gcc-urlifier.h"
      60              : 
      61              : /* For lang_hooks.types.type_for_mode.  */
      62              : #include "langhooks.h"
      63              : 
      64              : /* The names of each internal function, indexed by function number.  */
      65              : const char *const internal_fn_name_array[] = {
      66              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) #CODE,
      67              : #include "internal-fn.def"
      68              :   "<invalid-fn>"
      69              : };
      70              : 
      71              : /* The ECF_* flags of each internal function, indexed by function number.  */
      72              : const int internal_fn_flags_array[] = {
      73              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) FLAGS,
      74              : #include "internal-fn.def"
      75              :   0
      76              : };
      77              : 
      78              : /* Return the internal function called NAME, or IFN_LAST if there's
      79              :    no such function.  */
      80              : 
      81              : internal_fn
      82           16 : lookup_internal_fn (const char *name)
      83              : {
      84           16 :   typedef hash_map<nofree_string_hash, internal_fn> name_to_fn_map_type;
      85           16 :   static name_to_fn_map_type *name_to_fn_map;
      86              : 
      87           16 :   if (!name_to_fn_map)
      88              :     {
      89            7 :       name_to_fn_map = new name_to_fn_map_type (IFN_LAST);
      90         2079 :       for (unsigned int i = 0; i < IFN_LAST; ++i)
      91         4144 :         name_to_fn_map->put (internal_fn_name (internal_fn (i)),
      92         2072 :                              internal_fn (i));
      93              :     }
      94           16 :   internal_fn *entry = name_to_fn_map->get (name);
      95           16 :   return entry ? *entry : IFN_LAST;
      96              : }
      97              : 
      98              : /* Geven an internal_fn IFN that is a widening function, return its
      99              :    corresponding LO and HI internal_fns.  */
     100              : 
     101              : extern void
     102        70627 : lookup_hilo_internal_fn (internal_fn ifn, internal_fn *lo, internal_fn *hi)
     103              : {
     104        70627 :   gcc_assert (widening_fn_p (ifn));
     105              : 
     106        70627 :   switch (ifn)
     107              :     {
     108            0 :     default:
     109            0 :       gcc_unreachable ();
     110              : #define DEF_INTERNAL_FN(NAME, FLAGS, TYPE)
     111              : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T)   \
     112              :     case IFN_##NAME:                                            \
     113              :       *lo = internal_fn (IFN_##NAME##_LO);                      \
     114              :       *hi = internal_fn (IFN_##NAME##_HI);                      \
     115              :       break;
     116              : #include "internal-fn.def"
     117              :     }
     118        70627 : }
     119              : 
     120              : /* Given an internal_fn IFN that is a widening function, return its
     121              :    corresponding _EVEN and _ODD internal_fns in *EVEN and *ODD.  */
     122              : 
     123              : extern void
     124        70627 : lookup_evenodd_internal_fn (internal_fn ifn, internal_fn *even,
     125              :                             internal_fn *odd)
     126              : {
     127        70627 :   gcc_assert (widening_fn_p (ifn));
     128              : 
     129        70627 :   switch (ifn)
     130              :     {
     131            0 :     default:
     132            0 :       gcc_unreachable ();
     133              : #define DEF_INTERNAL_FN(NAME, FLAGS, TYPE)
     134              : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T)   \
     135              :     case IFN_##NAME:                                            \
     136              :       *even = internal_fn (IFN_##NAME##_EVEN);                  \
     137              :       *odd = internal_fn (IFN_##NAME##_ODD);                    \
     138              :       break;
     139              : #include "internal-fn.def"
     140              :     }
     141        70627 : }
     142              : 
     143              : 
     144              : /* Fnspec of each internal function, indexed by function number.  */
     145              : const_tree internal_fn_fnspec_array[IFN_LAST + 1];
     146              : 
     147              : void
     148       294223 : init_internal_fns ()
     149              : {
     150              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
     151              :   if (FNSPEC) internal_fn_fnspec_array[IFN_##CODE] = \
     152              :     build_string ((int) sizeof (FNSPEC) - 1, FNSPEC ? FNSPEC : "");
     153              : #include "internal-fn.def"
     154       294223 :   internal_fn_fnspec_array[IFN_LAST] = 0;
     155       294223 : }
     156              : 
     157              : /* Create static initializers for the information returned by
     158              :    direct_internal_fn.  */
     159              : #define not_direct { -2, -2, false }
     160              : #define mask_load_direct { -1, 2, false }
     161              : #define load_lanes_direct { -1, -1, false }
     162              : #define mask_load_lanes_direct { -1, -1, false }
     163              : #define gather_load_direct { 3, 1, false }
     164              : #define strided_load_direct { -1, -1, false }
     165              : #define len_load_direct { -1, -1, false }
     166              : #define mask_len_load_direct { -1, 4, false }
     167              : #define mask_store_direct { 3, 2, false }
     168              : #define store_lanes_direct { 0, 0, false }
     169              : #define mask_store_lanes_direct { 0, 0, false }
     170              : #define vec_cond_mask_direct { 1, 0, false }
     171              : #define vec_cond_mask_len_direct { 1, 1, false }
     172              : #define vec_cond_direct { 2, 0, false }
     173              : #define scatter_store_direct { 3, 1, false }
     174              : #define strided_store_direct { 1, 1, false }
     175              : #define len_store_direct { 3, 3, false }
     176              : #define mask_len_store_direct { 4, 5, false }
     177              : #define vec_set_direct { 3, 3, false }
     178              : #define vec_extract_direct { 0, -1, false }
     179              : #define unary_direct { 0, 0, true }
     180              : #define unary_convert_direct { -1, 0, true }
     181              : #define binary_direct { 0, 0, true }
     182              : #define ternary_direct { 0, 0, true }
     183              : #define cond_unary_direct { 1, 1, true }
     184              : #define cond_binary_direct { 1, 1, true }
     185              : #define cond_ternary_direct { 1, 1, true }
     186              : #define cond_len_unary_direct { 1, 1, true }
     187              : #define cond_len_binary_direct { 1, 1, true }
     188              : #define cond_len_ternary_direct { 1, 1, true }
     189              : #define while_direct { 0, 2, false }
     190              : #define fold_extract_direct { 2, 2, false }
     191              : #define fold_len_extract_direct { 2, 2, false }
     192              : #define fold_left_direct { 1, 1, false }
     193              : #define mask_fold_left_direct { 1, 1, false }
     194              : #define mask_len_fold_left_direct { 1, 1, false }
     195              : #define check_ptrs_direct { 0, 0, false }
     196              : #define crc_direct { 1, -1, true }
     197              : #define reduc_sbool_direct { 0, 0, true }
     198              : #define select_vl_direct { 2, 0, false }
     199              : 
     200              : const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
     201              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
     202              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) TYPE##_direct,
     203              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
     204              :                                      UNSIGNED_OPTAB, TYPE) TYPE##_direct,
     205              : #include "internal-fn.def"
     206              :   not_direct
     207              : };
     208              : 
     209              : /* Like create_output_operand, but for callers that will use
     210              :    assign_call_lhs afterwards.  */
     211              : 
     212              : static void
     213        87714 : create_call_lhs_operand (expand_operand *op, rtx lhs_rtx, machine_mode mode)
     214              : {
     215              :   /* Do not assign directly to a promoted subreg, since there is no
     216              :      guarantee that the instruction will leave the upper bits of the
     217              :      register in the state required by SUBREG_PROMOTED_SIGN.  */
     218        87714 :   rtx dest = lhs_rtx;
     219        87714 :   if (dest && GET_CODE (dest) == SUBREG && SUBREG_PROMOTED_VAR_P (dest))
     220        87714 :     dest = NULL_RTX;
     221        87714 :   create_output_operand (op, dest, mode);
     222        87714 : }
     223              : 
     224              : /* Move the result of an expanded instruction into the lhs of a gimple call.
     225              :    LHS is the lhs of the call, LHS_RTX is its expanded form, and OP is the
     226              :    result of the expanded instruction.  OP should have been set up by
     227              :    create_call_lhs_operand.  */
     228              : 
     229              : static void
     230        87714 : assign_call_lhs (tree lhs, rtx lhs_rtx, expand_operand *op)
     231              : {
     232        87714 :   if (rtx_equal_p (lhs_rtx, op->value))
     233              :     return;
     234              : 
     235              :   /* If the return value has an integral type, convert the instruction
     236              :      result to that type.  This is useful for things that return an
     237              :      int regardless of the size of the input.  If the instruction result
     238              :      is smaller than required, assume that it is signed.
     239              : 
     240              :      If the return value has a nonintegral type, its mode must match
     241              :      the instruction result.  */
     242         3489 :   if (GET_CODE (lhs_rtx) == SUBREG && SUBREG_PROMOTED_VAR_P (lhs_rtx))
     243              :     {
     244              :       /* If this is a scalar in a register that is stored in a wider
     245              :          mode than the declared mode, compute the result into its
     246              :          declared mode and then convert to the wider mode.  */
     247            0 :       gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs)));
     248            0 :       rtx tmp = convert_to_mode (GET_MODE (lhs_rtx), op->value, 0);
     249            0 :       convert_move (SUBREG_REG (lhs_rtx), tmp,
     250            0 :                     SUBREG_PROMOTED_SIGN (lhs_rtx));
     251              :     }
     252         3489 :   else if (GET_MODE (lhs_rtx) == GET_MODE (op->value))
     253           40 :     emit_move_insn (lhs_rtx, op->value);
     254              :   else
     255              :     {
     256         3449 :       gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs)));
     257         3449 :       convert_move (lhs_rtx, op->value, 0);
     258              :     }
     259              : }
     260              : 
     261              : /* Expand STMT using instruction ICODE.  The instruction has NOUTPUTS
     262              :    output operands and NINPUTS input operands, where NOUTPUTS is either
     263              :    0 or 1.  The output operand (if any) comes first, followed by the
     264              :    NINPUTS input operands.  */
     265              : 
     266              : static void
     267        77152 : expand_fn_using_insn (gcall *stmt, insn_code icode, unsigned int noutputs,
     268              :                       unsigned int ninputs)
     269              : {
     270        77152 :   gcc_assert (icode != CODE_FOR_nothing);
     271              : 
     272        77152 :   expand_operand *ops = XALLOCAVEC (expand_operand, noutputs + ninputs);
     273        77152 :   unsigned int opno = 0;
     274        77152 :   rtx lhs_rtx = NULL_RTX;
     275        77152 :   tree lhs = gimple_call_lhs (stmt);
     276              : 
     277        77152 :   if (noutputs)
     278              :     {
     279        77152 :       gcc_assert (noutputs == 1);
     280        77152 :       if (lhs)
     281        77152 :         lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     282        77152 :       create_call_lhs_operand (&ops[opno], lhs_rtx,
     283        77152 :                                insn_data[icode].operand[opno].mode);
     284        77152 :       opno += 1;
     285              :     }
     286              :   else
     287            0 :     gcc_assert (!lhs);
     288              : 
     289       220502 :   for (unsigned int i = 0; i < ninputs; ++i)
     290              :     {
     291       143350 :       tree rhs = gimple_call_arg (stmt, i);
     292       143350 :       tree rhs_type = TREE_TYPE (rhs);
     293       143350 :       rtx rhs_rtx = expand_normal (rhs);
     294       143350 :       if (INTEGRAL_TYPE_P (rhs_type))
     295         7258 :         create_convert_operand_from (&ops[opno], rhs_rtx,
     296         7258 :                                      TYPE_MODE (rhs_type),
     297         7258 :                                      TYPE_UNSIGNED (rhs_type));
     298       136092 :       else if (TREE_CODE (rhs) == SSA_NAME
     299       110894 :                && SSA_NAME_IS_DEFAULT_DEF (rhs)
     300       140596 :                && VAR_P (SSA_NAME_VAR (rhs)))
     301          247 :         create_undefined_input_operand (&ops[opno], TYPE_MODE (rhs_type));
     302        55680 :       else if (VECTOR_BOOLEAN_TYPE_P (rhs_type)
     303         1519 :                && SCALAR_INT_MODE_P (TYPE_MODE (rhs_type))
     304       137364 :                && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (rhs_type)),
     305         1519 :                             TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ()))
     306              :         {
     307              :           /* Ensure that the vector bitmasks do not have excess bits.  */
     308          427 :           int nunits = TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ();
     309          427 :           rtx tmp = expand_binop (TYPE_MODE (rhs_type), and_optab, rhs_rtx,
     310          427 :                                   GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
     311              :                                   NULL_RTX, true, OPTAB_WIDEN);
     312          427 :           create_input_operand (&ops[opno], tmp, TYPE_MODE (rhs_type));
     313              :         }
     314              :       else
     315       135418 :         create_input_operand (&ops[opno], rhs_rtx, TYPE_MODE (rhs_type));
     316       143350 :       opno += 1;
     317              :     }
     318              : 
     319        77152 :   gcc_assert (opno == noutputs + ninputs);
     320        77152 :   expand_insn (icode, opno, ops);
     321        77152 :   if (lhs_rtx)
     322        77152 :     assign_call_lhs (lhs, lhs_rtx, &ops[0]);
     323        77152 : }
     324              : 
     325              : /* ARRAY_TYPE is an array of vector modes.  Return the associated insn
     326              :    for load-lanes-style optab OPTAB, or CODE_FOR_nothing if none.  */
     327              : 
     328              : static enum insn_code
     329            0 : get_multi_vector_move (tree array_type, convert_optab optab)
     330              : {
     331            0 :   machine_mode imode;
     332            0 :   machine_mode vmode;
     333              : 
     334            0 :   gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
     335            0 :   imode = TYPE_MODE (array_type);
     336            0 :   vmode = TYPE_MODE (TREE_TYPE (array_type));
     337              : 
     338            0 :   return convert_optab_handler (optab, imode, vmode);
     339              : }
     340              : 
     341              : /* Add mask, else, and len arguments according to the STMT.  */
     342              : 
     343              : static unsigned int
     344         1401 : add_mask_else_and_len_args (expand_operand *ops, unsigned int opno, gcall *stmt)
     345              : {
     346         1401 :   internal_fn ifn = gimple_call_internal_fn (stmt);
     347         1401 :   int len_index = internal_fn_len_index (ifn);
     348              :   /* BIAS is always consecutive next of LEN.  */
     349         1401 :   int bias_index = len_index + 1;
     350         1401 :   int mask_index = internal_fn_mask_index (ifn);
     351              : 
     352              :   /* The order of arguments is always {mask, else, len, bias}.  */
     353         1401 :   if (mask_index >= 0)
     354              :     {
     355         1401 :       tree mask = gimple_call_arg (stmt, mask_index);
     356         1401 :       rtx mask_rtx = expand_normal (mask);
     357              : 
     358         1401 :       tree mask_type = TREE_TYPE (mask);
     359         1401 :       if (VECTOR_BOOLEAN_TYPE_P (mask_type)
     360         1400 :           && SCALAR_INT_MODE_P (TYPE_MODE (mask_type))
     361         2445 :           && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (mask_type)),
     362         2198 :                        TYPE_VECTOR_SUBPARTS (mask_type).to_constant ()))
     363              :         {
     364              :           /* Ensure that the vector bitmasks do not have excess bits.  */
     365          247 :           int nunits = TYPE_VECTOR_SUBPARTS (mask_type).to_constant ();
     366          247 :           mask_rtx = expand_binop (TYPE_MODE (mask_type), and_optab, mask_rtx,
     367          247 :                                    GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
     368              :                                    NULL_RTX, true, OPTAB_WIDEN);
     369              :         }
     370              : 
     371         1401 :       create_input_operand (&ops[opno++], mask_rtx,
     372         1401 :                             TYPE_MODE (TREE_TYPE (mask)));
     373              :     }
     374              : 
     375         1401 :   int els_index = internal_fn_else_index (ifn);
     376         1401 :   if (els_index >= 0)
     377              :     {
     378          675 :       tree els = gimple_call_arg (stmt, els_index);
     379          675 :       tree els_type = TREE_TYPE (els);
     380          675 :       if (TREE_CODE (els) == SSA_NAME
     381            0 :           && SSA_NAME_IS_DEFAULT_DEF (els)
     382          675 :           && VAR_P (SSA_NAME_VAR (els)))
     383            0 :         create_undefined_input_operand (&ops[opno++], TYPE_MODE (els_type));
     384              :       else
     385              :         {
     386          675 :           rtx els_rtx = expand_normal (els);
     387          675 :           create_input_operand (&ops[opno++], els_rtx, TYPE_MODE (els_type));
     388              :         }
     389              :     }
     390         1401 :   if (len_index >= 0)
     391              :     {
     392            0 :       tree len = gimple_call_arg (stmt, len_index);
     393            0 :       rtx len_rtx = expand_normal (len);
     394            0 :       create_convert_operand_from (&ops[opno++], len_rtx,
     395            0 :                                    TYPE_MODE (TREE_TYPE (len)),
     396            0 :                                    TYPE_UNSIGNED (TREE_TYPE (len)));
     397            0 :       tree biast = gimple_call_arg (stmt, bias_index);
     398            0 :       rtx bias = expand_normal (biast);
     399            0 :       create_input_operand (&ops[opno++], bias, QImode);
     400              :     }
     401         1401 :   return opno;
     402              : }
     403              : 
     404              : /* Expand LOAD_LANES call STMT using optab OPTAB.  */
     405              : 
     406              : static void
     407            0 : expand_load_lanes_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
     408              : {
     409            0 :   class expand_operand ops[2];
     410            0 :   tree type, lhs, rhs;
     411            0 :   rtx target, mem;
     412              : 
     413            0 :   lhs = gimple_call_lhs (stmt);
     414            0 :   rhs = gimple_call_arg (stmt, 0);
     415            0 :   type = TREE_TYPE (lhs);
     416              : 
     417            0 :   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     418            0 :   mem = expand_normal (rhs);
     419              : 
     420            0 :   gcc_assert (MEM_P (mem));
     421            0 :   PUT_MODE (mem, TYPE_MODE (type));
     422              : 
     423            0 :   create_call_lhs_operand (&ops[0], target, TYPE_MODE (type));
     424            0 :   create_fixed_operand (&ops[1], mem);
     425            0 :   expand_insn (get_multi_vector_move (type, optab), 2, ops);
     426            0 :   assign_call_lhs (lhs, target, &ops[0]);
     427            0 : }
     428              : 
     429              : /* Expand STORE_LANES call STMT using optab OPTAB.  */
     430              : 
     431              : static void
     432            0 : expand_store_lanes_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
     433              : {
     434            0 :   class expand_operand ops[2];
     435            0 :   tree type, lhs, rhs;
     436            0 :   rtx target, reg;
     437              : 
     438            0 :   lhs = gimple_call_lhs (stmt);
     439            0 :   rhs = gimple_call_arg (stmt, 0);
     440            0 :   type = TREE_TYPE (rhs);
     441              : 
     442            0 :   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     443            0 :   reg = expand_normal (rhs);
     444              : 
     445            0 :   gcc_assert (MEM_P (target));
     446            0 :   PUT_MODE (target, TYPE_MODE (type));
     447              : 
     448            0 :   create_fixed_operand (&ops[0], target);
     449            0 :   create_input_operand (&ops[1], reg, TYPE_MODE (type));
     450            0 :   expand_insn (get_multi_vector_move (type, optab), 2, ops);
     451            0 : }
     452              : 
     453              : static void
     454            0 : expand_ANNOTATE (internal_fn, gcall *)
     455              : {
     456            0 :   gcc_unreachable ();
     457              : }
     458              : 
     459              : /* This should get expanded in omp_device_lower pass.  */
     460              : 
     461              : static void
     462            0 : expand_GOMP_USE_SIMT (internal_fn, gcall *)
     463              : {
     464            0 :   gcc_unreachable ();
     465              : }
     466              : 
     467              : /* This should get expanded in omp_device_lower pass.  */
     468              : 
     469              : static void
     470            0 : expand_GOMP_SIMT_ENTER (internal_fn, gcall *)
     471              : {
     472            0 :   gcc_unreachable ();
     473              : }
     474              : 
     475              : /* Allocate per-lane storage and begin non-uniform execution region.  */
     476              : 
     477              : static void
     478            0 : expand_GOMP_SIMT_ENTER_ALLOC (internal_fn, gcall *stmt)
     479              : {
     480            0 :   rtx target;
     481            0 :   tree lhs = gimple_call_lhs (stmt);
     482            0 :   if (lhs)
     483            0 :     target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     484              :   else
     485            0 :     target = gen_reg_rtx (Pmode);
     486            0 :   rtx size = expand_normal (gimple_call_arg (stmt, 0));
     487            0 :   rtx align = expand_normal (gimple_call_arg (stmt, 1));
     488            0 :   class expand_operand ops[3];
     489            0 :   create_call_lhs_operand (&ops[0], target, Pmode);
     490            0 :   create_input_operand (&ops[1], size, Pmode);
     491            0 :   create_input_operand (&ops[2], align, Pmode);
     492            0 :   gcc_assert (targetm.have_omp_simt_enter ());
     493            0 :   expand_insn (targetm.code_for_omp_simt_enter, 3, ops);
     494            0 :   assign_call_lhs (lhs, target, &ops[0]);
     495            0 : }
     496              : 
     497              : /* Deallocate per-lane storage and leave non-uniform execution region.  */
     498              : 
     499              : static void
     500            0 : expand_GOMP_SIMT_EXIT (internal_fn, gcall *stmt)
     501              : {
     502            0 :   gcc_checking_assert (!gimple_call_lhs (stmt));
     503            0 :   rtx arg = expand_normal (gimple_call_arg (stmt, 0));
     504            0 :   class expand_operand ops[1];
     505            0 :   create_input_operand (&ops[0], arg, Pmode);
     506            0 :   gcc_assert (targetm.have_omp_simt_exit ());
     507            0 :   expand_insn (targetm.code_for_omp_simt_exit, 1, ops);
     508            0 : }
     509              : 
     510              : /* Lane index on SIMT targets: thread index in the warp on NVPTX.  On targets
     511              :    without SIMT execution this should be expanded in omp_device_lower pass.  */
     512              : 
     513              : static void
     514            0 : expand_GOMP_SIMT_LANE (internal_fn, gcall *stmt)
     515              : {
     516            0 :   tree lhs = gimple_call_lhs (stmt);
     517            0 :   if (!lhs)
     518              :     return;
     519              : 
     520            0 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     521            0 :   gcc_assert (targetm.have_omp_simt_lane ());
     522            0 :   emit_insn (targetm.gen_omp_simt_lane (target));
     523              : }
     524              : 
     525              : /* This should get expanded in omp_device_lower pass.  */
     526              : 
     527              : static void
     528            0 : expand_GOMP_SIMT_VF (internal_fn, gcall *)
     529              : {
     530            0 :   gcc_unreachable ();
     531              : }
     532              : 
     533              : /* This should get expanded in omp_device_lower pass.  */
     534              : 
     535              : static void
     536            0 : expand_GOMP_MAX_VF (internal_fn, gcall *)
     537              : {
     538            0 :   gcc_unreachable ();
     539              : }
     540              : 
     541              : /* This should get expanded in omp_device_lower pass.  */
     542              : 
     543              : static void
     544            0 : expand_GOMP_TARGET_REV (internal_fn, gcall *)
     545              : {
     546            0 :   gcc_unreachable ();
     547              : }
     548              : 
     549              : /* Lane index of the first SIMT lane that supplies a non-zero argument.
     550              :    This is a SIMT counterpart to GOMP_SIMD_LAST_LANE, used to represent the
     551              :    lane that executed the last iteration for handling OpenMP lastprivate.  */
     552              : 
     553              : static void
     554            0 : expand_GOMP_SIMT_LAST_LANE (internal_fn, gcall *stmt)
     555              : {
     556            0 :   tree lhs = gimple_call_lhs (stmt);
     557            0 :   if (!lhs)
     558            0 :     return;
     559              : 
     560            0 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     561            0 :   rtx cond = expand_normal (gimple_call_arg (stmt, 0));
     562            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
     563            0 :   class expand_operand ops[2];
     564            0 :   create_call_lhs_operand (&ops[0], target, mode);
     565            0 :   create_input_operand (&ops[1], cond, mode);
     566            0 :   gcc_assert (targetm.have_omp_simt_last_lane ());
     567            0 :   expand_insn (targetm.code_for_omp_simt_last_lane, 2, ops);
     568            0 :   assign_call_lhs (lhs, target, &ops[0]);
     569              : }
     570              : 
     571              : /* Non-transparent predicate used in SIMT lowering of OpenMP "ordered".  */
     572              : 
     573              : static void
     574            0 : expand_GOMP_SIMT_ORDERED_PRED (internal_fn, gcall *stmt)
     575              : {
     576            0 :   tree lhs = gimple_call_lhs (stmt);
     577            0 :   if (!lhs)
     578            0 :     return;
     579              : 
     580            0 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     581            0 :   rtx ctr = expand_normal (gimple_call_arg (stmt, 0));
     582            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
     583            0 :   class expand_operand ops[2];
     584            0 :   create_call_lhs_operand (&ops[0], target, mode);
     585            0 :   create_input_operand (&ops[1], ctr, mode);
     586            0 :   gcc_assert (targetm.have_omp_simt_ordered ());
     587            0 :   expand_insn (targetm.code_for_omp_simt_ordered, 2, ops);
     588            0 :   assign_call_lhs (lhs, target, &ops[0]);
     589              : }
     590              : 
     591              : /* "Or" boolean reduction across SIMT lanes: return non-zero in all lanes if
     592              :    any lane supplies a non-zero argument.  */
     593              : 
     594              : static void
     595            0 : expand_GOMP_SIMT_VOTE_ANY (internal_fn, gcall *stmt)
     596              : {
     597            0 :   tree lhs = gimple_call_lhs (stmt);
     598            0 :   if (!lhs)
     599            0 :     return;
     600              : 
     601            0 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     602            0 :   rtx cond = expand_normal (gimple_call_arg (stmt, 0));
     603            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
     604            0 :   class expand_operand ops[2];
     605            0 :   create_call_lhs_operand (&ops[0], target, mode);
     606            0 :   create_input_operand (&ops[1], cond, mode);
     607            0 :   gcc_assert (targetm.have_omp_simt_vote_any ());
     608            0 :   expand_insn (targetm.code_for_omp_simt_vote_any, 2, ops);
     609            0 :   assign_call_lhs (lhs, target, &ops[0]);
     610              : }
     611              : 
     612              : /* Exchange between SIMT lanes with a "butterfly" pattern: source lane index
     613              :    is destination lane index XOR given offset.  */
     614              : 
     615              : static void
     616            0 : expand_GOMP_SIMT_XCHG_BFLY (internal_fn, gcall *stmt)
     617              : {
     618            0 :   tree lhs = gimple_call_lhs (stmt);
     619            0 :   if (!lhs)
     620            0 :     return;
     621              : 
     622            0 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     623            0 :   rtx src = expand_normal (gimple_call_arg (stmt, 0));
     624            0 :   rtx idx = expand_normal (gimple_call_arg (stmt, 1));
     625            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
     626            0 :   class expand_operand ops[3];
     627            0 :   create_call_lhs_operand (&ops[0], target, mode);
     628            0 :   create_input_operand (&ops[1], src, mode);
     629            0 :   create_input_operand (&ops[2], idx, SImode);
     630            0 :   gcc_assert (targetm.have_omp_simt_xchg_bfly ());
     631            0 :   expand_insn (targetm.code_for_omp_simt_xchg_bfly, 3, ops);
     632            0 :   assign_call_lhs (lhs, target, &ops[0]);
     633              : }
     634              : 
     635              : /* Exchange between SIMT lanes according to given source lane index.  */
     636              : 
     637              : static void
     638            0 : expand_GOMP_SIMT_XCHG_IDX (internal_fn, gcall *stmt)
     639              : {
     640            0 :   tree lhs = gimple_call_lhs (stmt);
     641            0 :   if (!lhs)
     642            0 :     return;
     643              : 
     644            0 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     645            0 :   rtx src = expand_normal (gimple_call_arg (stmt, 0));
     646            0 :   rtx idx = expand_normal (gimple_call_arg (stmt, 1));
     647            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
     648            0 :   class expand_operand ops[3];
     649            0 :   create_call_lhs_operand (&ops[0], target, mode);
     650            0 :   create_input_operand (&ops[1], src, mode);
     651            0 :   create_input_operand (&ops[2], idx, SImode);
     652            0 :   gcc_assert (targetm.have_omp_simt_xchg_idx ());
     653            0 :   expand_insn (targetm.code_for_omp_simt_xchg_idx, 3, ops);
     654            0 :   assign_call_lhs (lhs, target, &ops[0]);
     655              : }
     656              : 
     657              : /* This should get expanded in adjust_simduid_builtins.  */
     658              : 
     659              : static void
     660            0 : expand_GOMP_SIMD_LANE (internal_fn, gcall *)
     661              : {
     662            0 :   gcc_unreachable ();
     663              : }
     664              : 
     665              : /* This should get expanded in adjust_simduid_builtins.  */
     666              : 
     667              : static void
     668            0 : expand_GOMP_SIMD_VF (internal_fn, gcall *)
     669              : {
     670            0 :   gcc_unreachable ();
     671              : }
     672              : 
     673              : /* This should get expanded in adjust_simduid_builtins.  */
     674              : 
     675              : static void
     676            0 : expand_GOMP_SIMD_LAST_LANE (internal_fn, gcall *)
     677              : {
     678            0 :   gcc_unreachable ();
     679              : }
     680              : 
     681              : /* This should get expanded in adjust_simduid_builtins.  */
     682              : 
     683              : static void
     684            0 : expand_GOMP_SIMD_ORDERED_START (internal_fn, gcall *)
     685              : {
     686            0 :   gcc_unreachable ();
     687              : }
     688              : 
     689              : /* This should get expanded in adjust_simduid_builtins.  */
     690              : 
     691              : static void
     692            0 : expand_GOMP_SIMD_ORDERED_END (internal_fn, gcall *)
     693              : {
     694            0 :   gcc_unreachable ();
     695              : }
     696              : 
     697              : /* This should get expanded in gimplify_omp_dispatch.  */
     698              : 
     699              : static void
     700            0 : expand_GOMP_DISPATCH (internal_fn, gcall *)
     701              : {
     702            0 :   gcc_unreachable ();
     703              : }
     704              : 
     705              : /* This should get expanded in the sanopt pass.  */
     706              : 
     707              : static void
     708            0 : expand_UBSAN_NULL (internal_fn, gcall *)
     709              : {
     710            0 :   gcc_unreachable ();
     711              : }
     712              : 
     713              : /* This should get expanded in the sanopt pass.  */
     714              : 
     715              : static void
     716            0 : expand_UBSAN_BOUNDS (internal_fn, gcall *)
     717              : {
     718            0 :   gcc_unreachable ();
     719              : }
     720              : 
     721              : /* This should get expanded in the sanopt pass.  */
     722              : 
     723              : static void
     724            0 : expand_UBSAN_VPTR (internal_fn, gcall *)
     725              : {
     726            0 :   gcc_unreachable ();
     727              : }
     728              : 
     729              : /* This should get expanded in the sanopt pass.  */
     730              : 
     731              : static void
     732            0 : expand_UBSAN_PTR (internal_fn, gcall *)
     733              : {
     734            0 :   gcc_unreachable ();
     735              : }
     736              : 
     737              : /* This should get expanded in the sanopt pass.  */
     738              : 
     739              : static void
     740            0 : expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
     741              : {
     742            0 :   gcc_unreachable ();
     743              : }
     744              : 
     745              : /* This should get expanded in the sanopt pass.  */
     746              : 
     747              : static void
     748            0 : expand_HWASAN_CHECK (internal_fn, gcall *)
     749              : {
     750            0 :   gcc_unreachable ();
     751              : }
     752              : 
     753              : /* For hwasan stack tagging:
     754              :    Tag memory which is dynamically allocated.  */
     755              : static void
     756            0 : expand_HWASAN_ALLOCA_POISON (internal_fn, gcall *gc)
     757              : {
     758            0 :   gcc_assert (ptr_mode == Pmode);
     759            0 :   tree g_target = gimple_call_lhs (gc);
     760            0 :   tree g_ptr = gimple_call_arg (gc, 0);
     761            0 :   tree g_size = gimple_call_arg (gc, 1);
     762              : 
     763              :   /* There is no target; this happens, usually, when we have an alloca of zero
     764              :      size.  */
     765            0 :   if (!g_target)
     766              :     return;
     767            0 :   rtx target = expand_normal (g_target);
     768            0 :   rtx ptr = expand_normal (g_ptr);
     769            0 :   rtx size = expand_normal (g_size);
     770              : 
     771              :   /* No size, nothing to do.  */
     772            0 :   if (size == const0_rtx)
     773              :     return;
     774              : 
     775              :   /* Get new tag for the alloca'd memory.
     776              :      Doing a regular add_tag () like so:
     777              :         rtx tag = targetm.memtag.add_tag (hwasan_frame_base (), 0,
     778              :                                           hwasan_current_frame_tag ());
     779              :      gets a new tag, which can be used for tagging memory.  But for alloca, we
     780              :      need both tagged memory and a tagged pointer to pass to consumers.  Invoke
     781              :      insert_random_tag () instead to add a random tag to ptr to get a tagged
     782              :      pointer that will work for both purposes.  */
     783            0 :   rtx tagged_ptr
     784            0 :     = force_reg (Pmode, targetm.memtag.insert_random_tag (ptr, NULL_RTX));
     785            0 :   rtx tag = targetm.memtag.extract_tag (tagged_ptr, NULL_RTX);
     786              : 
     787            0 :   if (memtag_sanitize_p ())
     788              :     {
     789              :       /* Need to put the tagged ptr into the `target` RTX for consumers
     790              :          of alloca'd memory.  */
     791            0 :       if (tagged_ptr != target)
     792            0 :         emit_move_insn (target, tagged_ptr);
     793              :       /* Tag the memory.  */
     794            0 :       emit_insn (targetm.gen_tag_memory (ptr, tag, size));
     795            0 :       hwasan_increment_frame_tag ();
     796              :     }
     797              :   else
     798            0 :     gcc_unreachable ();
     799              : }
     800              : 
     801              : /* For hwasan stack tagging:
     802              :    Clear tags on the dynamically allocated space.
     803              :    For use after an object dynamically allocated on the stack goes out of
     804              :    scope.  */
     805              : static void
     806            0 : expand_HWASAN_ALLOCA_UNPOISON (internal_fn, gcall *gc)
     807              : {
     808            0 :   gcc_assert (Pmode == ptr_mode);
     809            0 :   tree restored_position = gimple_call_arg (gc, 0);
     810            0 :   rtx restored_rtx = expand_expr (restored_position, NULL_RTX, VOIDmode,
     811              :                                   EXPAND_NORMAL);
     812            0 :   rtx off = expand_simple_binop (Pmode, MINUS, restored_rtx,
     813              :                                  stack_pointer_rtx, NULL_RTX, 0,
     814              :                                  OPTAB_WIDEN);
     815              : 
     816            0 :   if (memtag_sanitize_p ())
     817            0 :     emit_insn (targetm.gen_tag_memory (virtual_stack_dynamic_rtx,
     818              :                                        HWASAN_STACK_BACKGROUND,
     819              :                                        off));
     820              :   else
     821              :     {
     822            0 :       rtx func = init_one_libfunc ("__hwasan_tag_memory");
     823            0 :       emit_library_call_value (func, NULL_RTX, LCT_NORMAL, VOIDmode,
     824            0 :                                virtual_stack_dynamic_rtx, Pmode,
     825              :                                HWASAN_STACK_BACKGROUND, QImode,
     826            0 :                                off, Pmode);
     827              :     }
     828            0 : }
     829              : 
     830              : /* For hwasan stack tagging:
     831              :    Return a tag to be used for a dynamic allocation.  */
     832              : static void
     833            0 : expand_HWASAN_CHOOSE_TAG (internal_fn, gcall *gc)
     834              : {
     835            0 :   tree tag = gimple_call_lhs (gc);
     836            0 :   rtx target = expand_expr (tag, NULL_RTX, VOIDmode, EXPAND_NORMAL);
     837            0 :   machine_mode mode = GET_MODE (target);
     838            0 :   gcc_assert (mode == QImode);
     839              : 
     840            0 :   rtx base_tag = targetm.memtag.extract_tag (hwasan_frame_base (), NULL_RTX);
     841            0 :   gcc_assert (base_tag);
     842            0 :   rtx tag_offset = gen_int_mode (hwasan_current_frame_tag (), QImode);
     843            0 :   rtx chosen_tag = expand_simple_binop (QImode, PLUS, base_tag, tag_offset,
     844              :                                         target, /* unsignedp = */1,
     845              :                                         OPTAB_WIDEN);
     846            0 :   chosen_tag = hwasan_truncate_to_tag_size (chosen_tag, target);
     847              : 
     848              :   /* Really need to put the tag into the `target` RTX.  */
     849            0 :   if (chosen_tag != target)
     850              :     {
     851            0 :       rtx temp = chosen_tag;
     852            0 :       gcc_assert (GET_MODE (chosen_tag) == mode);
     853            0 :       emit_move_insn (target, temp);
     854              :     }
     855              : 
     856            0 :   hwasan_increment_frame_tag ();
     857            0 : }
     858              : 
     859              : /* For hwasan stack tagging:
     860              :    Tag a region of space in the shadow stack according to the base pointer of
     861              :    an object on the stack.  N.b. the length provided in the internal call is
     862              :    required to be aligned to HWASAN_TAG_GRANULE_SIZE.  */
     863              : static void
     864            0 : expand_HWASAN_MARK (internal_fn, gcall *gc)
     865              : {
     866            0 :   gcc_assert (ptr_mode == Pmode);
     867            0 :   HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (gc, 0));
     868            0 :   bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
     869              : 
     870            0 :   tree base = gimple_call_arg (gc, 1);
     871            0 :   gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
     872            0 :   rtx base_rtx = expand_normal (base);
     873              : 
     874            0 :   rtx tag = is_poison ? HWASAN_STACK_BACKGROUND
     875            0 :     : targetm.memtag.extract_tag (base_rtx, NULL_RTX);
     876            0 :   rtx address = targetm.memtag.untagged_pointer (base_rtx, NULL_RTX);
     877              : 
     878            0 :   tree len = gimple_call_arg (gc, 2);
     879            0 :   rtx r_len = expand_normal (len);
     880              : 
     881            0 :   if (memtag_sanitize_p ())
     882            0 :     emit_insn (targetm.gen_tag_memory (address, tag, r_len));
     883              :   else
     884              :     {
     885            0 :       rtx func = init_one_libfunc ("__hwasan_tag_memory");
     886            0 :       emit_library_call (func, LCT_NORMAL, VOIDmode, address, Pmode,
     887            0 :                          tag, QImode, r_len, Pmode);
     888              :     }
     889            0 : }
     890              : 
     891              : /* For hwasan stack tagging:
     892              :    Store a tag into a pointer.  */
     893              : static void
     894            0 : expand_HWASAN_SET_TAG (internal_fn, gcall *gc)
     895              : {
     896            0 :   gcc_assert (ptr_mode == Pmode);
     897            0 :   tree g_target = gimple_call_lhs (gc);
     898            0 :   tree g_ptr = gimple_call_arg (gc, 0);
     899            0 :   tree g_tag = gimple_call_arg (gc, 1);
     900              : 
     901            0 :   rtx ptr = expand_normal (g_ptr);
     902            0 :   rtx tag = expand_expr (g_tag, NULL_RTX, QImode, EXPAND_NORMAL);
     903            0 :   rtx target = expand_normal (g_target);
     904              : 
     905            0 :   rtx untagged = targetm.memtag.untagged_pointer (ptr, target);
     906            0 :   rtx tagged_value = targetm.memtag.set_tag (untagged, tag, target);
     907            0 :   if (tagged_value != target)
     908            0 :     emit_move_insn (target, tagged_value);
     909            0 : }
     910              : 
     911              : /* This should get expanded in the sanopt pass.  */
     912              : 
     913              : static void
     914            0 : expand_ASAN_CHECK (internal_fn, gcall *)
     915              : {
     916            0 :   gcc_unreachable ();
     917              : }
     918              : 
     919              : /* This should get expanded in the sanopt pass.  */
     920              : 
     921              : static void
     922            0 : expand_ASAN_MARK (internal_fn, gcall *)
     923              : {
     924            0 :   gcc_unreachable ();
     925              : }
     926              : 
     927              : /* This should get expanded in the sanopt pass.  */
     928              : 
     929              : static void
     930            0 : expand_ASAN_POISON (internal_fn, gcall *)
     931              : {
     932            0 :   gcc_unreachable ();
     933              : }
     934              : 
     935              : /* This should get expanded in the sanopt pass.  */
     936              : 
     937              : static void
     938            0 : expand_ASAN_POISON_USE (internal_fn, gcall *)
     939              : {
     940            0 :   gcc_unreachable ();
     941              : }
     942              : 
     943              : /* This should get expanded in the tsan pass.  */
     944              : 
     945              : static void
     946            0 : expand_TSAN_FUNC_EXIT (internal_fn, gcall *)
     947              : {
     948            0 :   gcc_unreachable ();
     949              : }
     950              : 
     951              : /* This should get expanded in the lower pass.  */
     952              : 
     953              : static void
     954           25 : expand_FALLTHROUGH (internal_fn, gcall *call)
     955              : {
     956           25 :   auto_urlify_attributes sentinel;
     957           25 :   error_at (gimple_location (call),
     958              :             "invalid use of attribute %<fallthrough%>");
     959           25 : }
     960              : 
     961              : /* Return minimum precision needed to represent all values
     962              :    of ARG in SIGNed integral type.  */
     963              : 
     964              : static int
     965       156858 : get_min_precision (tree arg, signop sign)
     966              : {
     967       156858 :   int prec = TYPE_PRECISION (TREE_TYPE (arg));
     968       156858 :   int cnt = 0;
     969       156858 :   signop orig_sign = sign;
     970       156858 :   if (TREE_CODE (arg) == INTEGER_CST)
     971              :     {
     972        40630 :       int p;
     973        40630 :       if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
     974              :         {
     975        14548 :           widest_int w = wi::to_widest (arg);
     976        14548 :           w = wi::ext (w, prec, sign);
     977        14548 :           p = wi::min_precision (w, sign);
     978        14548 :         }
     979              :       else
     980        26082 :         p = wi::min_precision (wi::to_wide (arg), sign);
     981        40630 :       return MIN (p, prec);
     982              :     }
     983       116183 :   while (CONVERT_EXPR_P (arg)
     984         7371 :          && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
     985       130925 :          && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
     986              :     {
     987         7371 :       arg = TREE_OPERAND (arg, 0);
     988         7371 :       if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
     989              :         {
     990         1109 :           if (TYPE_UNSIGNED (TREE_TYPE (arg)))
     991              :             sign = UNSIGNED;
     992          805 :           else if (sign == UNSIGNED
     993          805 :                    && (get_range_pos_neg (arg,
     994              :                                           currently_expanding_gimple_stmt)
     995              :                        != 1))
     996           45 :             return prec + (orig_sign != sign);
     997         1064 :           prec = TYPE_PRECISION (TREE_TYPE (arg));
     998              :         }
     999         7326 :       if (++cnt > 30)
    1000            0 :         return prec + (orig_sign != sign);
    1001              :     }
    1002       116183 :   if (CONVERT_EXPR_P (arg)
    1003            0 :       && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
    1004       116183 :       && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) > prec)
    1005              :     {
    1006              :       /* We have e.g. (unsigned short) y_2 where int y_2 = (int) x_1(D);
    1007              :          If y_2's min precision is smaller than prec, return that.  */
    1008            0 :       int oprec = get_min_precision (TREE_OPERAND (arg, 0), sign);
    1009            0 :       if (oprec < prec)
    1010            0 :         return oprec + (orig_sign != sign);
    1011              :     }
    1012       116183 :   if (TREE_CODE (arg) != SSA_NAME)
    1013            0 :     return prec + (orig_sign != sign);
    1014       116183 :   int_range_max r;
    1015       116183 :   gimple *cg = currently_expanding_gimple_stmt;
    1016       237949 :   while (!get_range_query (cfun)->range_of_expr (r, arg, cg)
    1017       121766 :          || r.varying_p ()
    1018       252800 :          || r.undefined_p ())
    1019              :     {
    1020       112499 :       gimple *g = SSA_NAME_DEF_STMT (arg);
    1021       112499 :       if (is_gimple_assign (g)
    1022       112499 :           && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
    1023              :         {
    1024         6684 :           tree t = gimple_assign_rhs1 (g);
    1025        13368 :           if (INTEGRAL_TYPE_P (TREE_TYPE (t))
    1026        12372 :               && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
    1027              :             {
    1028         5590 :               arg = t;
    1029         5590 :               if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
    1030              :                 {
    1031         5208 :                   if (TYPE_UNSIGNED (TREE_TYPE (arg)))
    1032              :                     sign = UNSIGNED;
    1033         2884 :                   else if (sign == UNSIGNED
    1034         2884 :                            && get_range_pos_neg (arg, g) != 1)
    1035            7 :                     return prec + (orig_sign != sign);
    1036         5201 :                   prec = TYPE_PRECISION (TREE_TYPE (arg));
    1037              :                 }
    1038         5583 :               if (++cnt > 30)
    1039            0 :                 return prec + (orig_sign != sign);
    1040         5583 :               continue;
    1041              :             }
    1042              :         }
    1043       106909 :       return prec + (orig_sign != sign);
    1044              :     }
    1045         9267 :   if (sign == TYPE_SIGN (TREE_TYPE (arg)))
    1046              :     {
    1047         8685 :       int p1 = wi::min_precision (r.lower_bound (), sign);
    1048         8685 :       int p2 = wi::min_precision (r.upper_bound (), sign);
    1049         8685 :       p1 = MAX (p1, p2);
    1050         8685 :       prec = MIN (prec, p1);
    1051              :     }
    1052         1140 :   else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
    1053              :     {
    1054          554 :       int p = wi::min_precision (r.upper_bound (), UNSIGNED);
    1055          582 :       prec = MIN (prec, p);
    1056              :     }
    1057         9267 :   return prec + (orig_sign != sign);
    1058       116183 : }
    1059              : 
    1060              : /* Helper for expand_*_overflow.  Set the __imag__ part to true
    1061              :    (1 except for signed:1 type, in which case store -1).  */
    1062              : 
    1063              : static void
    1064        82096 : expand_arith_set_overflow (tree lhs, rtx target)
    1065              : {
    1066        82096 :   if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
    1067        82096 :       && !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
    1068          202 :     write_complex_part (target, constm1_rtx, true, false);
    1069              :   else
    1070        81894 :     write_complex_part (target, const1_rtx, true, false);
    1071        82096 : }
    1072              : 
    1073              : /* Helper for expand_*_overflow.  Store RES into the __real__ part
    1074              :    of TARGET.  If RES has larger MODE than __real__ part of TARGET,
    1075              :    set the __imag__ part to 1 if RES doesn't fit into it.  Similarly
    1076              :    if LHS has smaller precision than its mode.  */
    1077              : 
    1078              : static void
    1079        72049 : expand_arith_overflow_result_store (tree lhs, rtx target,
    1080              :                                     scalar_int_mode mode, rtx res)
    1081              : {
    1082        72049 :   scalar_int_mode tgtmode
    1083       144098 :     = as_a <scalar_int_mode> (GET_MODE_INNER (GET_MODE (target)));
    1084        72049 :   rtx lres = res;
    1085        72049 :   if (tgtmode != mode)
    1086              :     {
    1087        18872 :       rtx_code_label *done_label = gen_label_rtx ();
    1088        18872 :       int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
    1089        18872 :       lres = convert_modes (tgtmode, mode, res, uns);
    1090        18872 :       gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
    1091        18872 :       do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns),
    1092              :                                EQ, true, mode, NULL_RTX, NULL, done_label,
    1093              :                                profile_probability::very_likely ());
    1094        18872 :       expand_arith_set_overflow (lhs, target);
    1095        18872 :       emit_label (done_label);
    1096              :     }
    1097        72049 :   int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
    1098        72049 :   int tgtprec = GET_MODE_PRECISION (tgtmode);
    1099        72049 :   if (prec < tgtprec)
    1100              :     {
    1101         3553 :       rtx_code_label *done_label = gen_label_rtx ();
    1102         3553 :       int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
    1103         3553 :       res = lres;
    1104         3553 :       if (uns)
    1105              :         {
    1106         2008 :           rtx mask
    1107         2008 :             = immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
    1108              :                                     tgtmode);
    1109         2008 :           lres = expand_simple_binop (tgtmode, AND, res, mask, NULL_RTX,
    1110              :                                       true, OPTAB_LIB_WIDEN);
    1111              :         }
    1112              :       else
    1113              :         {
    1114         1545 :           lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
    1115              :                                NULL_RTX, 1);
    1116         1545 :           lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
    1117              :                                NULL_RTX, 0);
    1118              :         }
    1119         3553 :       do_compare_rtx_and_jump (res, lres,
    1120              :                                EQ, true, tgtmode, NULL_RTX, NULL, done_label,
    1121              :                                profile_probability::very_likely ());
    1122         3553 :       expand_arith_set_overflow (lhs, target);
    1123         3553 :       emit_label (done_label);
    1124              :     }
    1125        72049 :   write_complex_part (target, lres, false, false);
    1126        72049 : }
    1127              : 
    1128              : /* Helper for expand_*_overflow.  Store RES into TARGET.  */
    1129              : 
    1130              : static void
    1131         4675 : expand_ubsan_result_store (tree lhs, rtx target, scalar_int_mode mode,
    1132              :                            rtx res, rtx_code_label *do_error)
    1133              : {
    1134         9296 :   if (BITINT_TYPE_P (TREE_TYPE (lhs))
    1135         4675 :       && TYPE_PRECISION (TREE_TYPE (lhs)) < GET_MODE_PRECISION (mode))
    1136              :     {
    1137           54 :       int uns = TYPE_UNSIGNED (TREE_TYPE (lhs));
    1138           54 :       int prec = TYPE_PRECISION (TREE_TYPE (lhs));
    1139           54 :       int tgtprec = GET_MODE_PRECISION (mode);
    1140           54 :       rtx resc = gen_reg_rtx (mode), lres;
    1141           54 :       emit_move_insn (resc, res);
    1142           54 :       if (uns)
    1143              :         {
    1144            0 :           rtx mask
    1145            0 :             = immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
    1146              :                                     mode);
    1147            0 :           lres = expand_simple_binop (mode, AND, res, mask, NULL_RTX,
    1148              :                                       true, OPTAB_LIB_WIDEN);
    1149              :         }
    1150              :       else
    1151              :         {
    1152           54 :           lres = expand_shift (LSHIFT_EXPR, mode, res, tgtprec - prec,
    1153              :                                NULL_RTX, 1);
    1154           54 :           lres = expand_shift (RSHIFT_EXPR, mode, lres, tgtprec - prec,
    1155              :                                NULL_RTX, 0);
    1156              :         }
    1157           54 :       if (lres != res)
    1158           54 :         emit_move_insn (res, lres);
    1159           54 :       do_compare_rtx_and_jump (res, resc,
    1160              :                                NE, true, mode, NULL_RTX, NULL, do_error,
    1161              :                                profile_probability::very_unlikely ());
    1162              :     }
    1163         4675 :   if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
    1164              :     /* If this is a scalar in a register that is stored in a wider mode
    1165              :        than the declared mode, compute the result into its declared mode
    1166              :        and then convert to the wider mode.  Our value is the computed
    1167              :        expression.  */
    1168            0 :     convert_move (SUBREG_REG (target), res, SUBREG_PROMOTED_SIGN (target));
    1169              :   else
    1170         4675 :     emit_move_insn (target, res);
    1171         4675 : }
    1172              : 
    1173              : /* Add sub/add overflow checking to the statement STMT.
    1174              :    CODE says whether the operation is +, or -.  */
    1175              : 
    1176              : void
    1177        39124 : expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
    1178              :                         tree arg0, tree arg1, bool unsr_p, bool uns0_p,
    1179              :                         bool uns1_p, bool is_ubsan, tree *datap)
    1180              : {
    1181        39124 :   rtx res, target = NULL_RTX;
    1182        39124 :   tree fn;
    1183        39124 :   rtx_code_label *done_label = gen_label_rtx ();
    1184        39124 :   rtx_code_label *do_error = gen_label_rtx ();
    1185        39124 :   do_pending_stack_adjust ();
    1186        39124 :   rtx op0 = expand_normal (arg0);
    1187        39124 :   rtx op1 = expand_normal (arg1);
    1188        39124 :   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
    1189        39124 :   int prec = GET_MODE_PRECISION (mode);
    1190        39124 :   rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
    1191        39124 :   bool do_xor = false;
    1192              : 
    1193        39124 :   if (is_ubsan)
    1194         3391 :     gcc_assert (!unsr_p && !uns0_p && !uns1_p);
    1195              : 
    1196        39124 :   if (lhs)
    1197              :     {
    1198        38596 :       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    1199        38596 :       if (!is_ubsan)
    1200        35733 :         write_complex_part (target, const0_rtx, true, false);
    1201              :     }
    1202              : 
    1203              :   /* We assume both operands and result have the same precision
    1204              :      here (GET_MODE_BITSIZE (mode)), S stands for signed type
    1205              :      with that precision, U for unsigned type with that precision,
    1206              :      sgn for unsigned most significant bit in that precision.
    1207              :      s1 is signed first operand, u1 is unsigned first operand,
    1208              :      s2 is signed second operand, u2 is unsigned second operand,
    1209              :      sr is signed result, ur is unsigned result and the following
    1210              :      rules say how to compute result (which is always result of
    1211              :      the operands as if both were unsigned, cast to the right
    1212              :      signedness) and how to compute whether operation overflowed.
    1213              : 
    1214              :      s1 + s2 -> sr
    1215              :         res = (S) ((U) s1 + (U) s2)
    1216              :         ovf = s2 < 0 ? res > s1 : res < s1 (or jump on overflow)
    1217              :      s1 - s2 -> sr
    1218              :         res = (S) ((U) s1 - (U) s2)
    1219              :         ovf = s2 < 0 ? res < s1 : res > s2 (or jump on overflow)
    1220              :      u1 + u2 -> ur
    1221              :         res = u1 + u2
    1222              :         ovf = res < u1 (or jump on carry, but RTL opts will handle it)
    1223              :      u1 - u2 -> ur
    1224              :         res = u1 - u2
    1225              :         ovf = res > u1 (or jump on carry, but RTL opts will handle it)
    1226              :      s1 + u2 -> sr
    1227              :         res = (S) ((U) s1 + u2)
    1228              :         ovf = ((U) res ^ sgn) < u2
    1229              :      s1 + u2 -> ur
    1230              :         t1 = (S) (u2 ^ sgn)
    1231              :         t2 = s1 + t1
    1232              :         res = (U) t2 ^ sgn
    1233              :         ovf = t1 < 0 ? t2 > s1 : t2 < s1 (or jump on overflow)
    1234              :      s1 - u2 -> sr
    1235              :         res = (S) ((U) s1 - u2)
    1236              :         ovf = u2 > ((U) s1 ^ sgn)
    1237              :      s1 - u2 -> ur
    1238              :         res = (U) s1 - u2
    1239              :         ovf = s1 < 0 || u2 > (U) s1
    1240              :      u1 - s2 -> sr
    1241              :         res = u1 - (U) s2
    1242              :         ovf = u1 >= ((U) s2 ^ sgn)
    1243              :      u1 - s2 -> ur
    1244              :         t1 = u1 ^ sgn
    1245              :         t2 = t1 - (U) s2
    1246              :         res = t2 ^ sgn
    1247              :         ovf = s2 < 0 ? (S) t2 < (S) t1 : (S) t2 > (S) t1 (or jump on overflow)
    1248              :      s1 + s2 -> ur
    1249              :         res = (U) s1 + (U) s2
    1250              :         ovf = s2 < 0 ? (s1 | (S) res) < 0) : (s1 & (S) res) < 0)
    1251              :      u1 + u2 -> sr
    1252              :         res = (S) (u1 + u2)
    1253              :         ovf = (U) res < u2 || res < 0
    1254              :      u1 - u2 -> sr
    1255              :         res = (S) (u1 - u2)
    1256              :         ovf = u1 >= u2 ? res < 0 : res >= 0
    1257              :      s1 - s2 -> ur
    1258              :         res = (U) s1 - (U) s2
    1259              :         ovf = s2 >= 0 ? ((s1 | (S) res) < 0) : ((s1 & (S) res) < 0)  */
    1260              : 
    1261        39124 :   if (code == PLUS_EXPR && uns0_p && !uns1_p)
    1262              :     {
    1263              :       /* PLUS_EXPR is commutative, if operand signedness differs,
    1264              :          canonicalize to the first operand being signed and second
    1265              :          unsigned to simplify following code.  */
    1266              :       std::swap (op0, op1);
    1267              :       std::swap (arg0, arg1);
    1268              :       uns0_p = false;
    1269              :       uns1_p = true;
    1270              :     }
    1271              : 
    1272              :   /* u1 +- u2 -> ur  */
    1273        38341 :   if (uns0_p && uns1_p && unsr_p)
    1274              :     {
    1275        20528 :       insn_code icode = optab_handler (code == PLUS_EXPR ? uaddv4_optab
    1276              :                                        : usubv4_optab, mode);
    1277        15421 :       if (icode != CODE_FOR_nothing)
    1278              :         {
    1279        14592 :           class expand_operand ops[4];
    1280        14592 :           rtx_insn *last = get_last_insn ();
    1281              : 
    1282        14592 :           res = gen_reg_rtx (mode);
    1283        14592 :           create_output_operand (&ops[0], res, mode);
    1284        14592 :           create_input_operand (&ops[1], op0, mode);
    1285        14592 :           create_input_operand (&ops[2], op1, mode);
    1286        14592 :           create_fixed_operand (&ops[3], do_error);
    1287        14592 :           if (maybe_expand_insn (icode, 4, ops))
    1288              :             {
    1289        14592 :               last = get_last_insn ();
    1290        14592 :               if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    1291        12256 :                   && JUMP_P (last)
    1292        12256 :                   && any_condjump_p (last)
    1293        26848 :                   && !find_reg_note (last, REG_BR_PROB, 0))
    1294        12256 :                 add_reg_br_prob_note (last,
    1295              :                                       profile_probability::very_unlikely ());
    1296        14592 :               emit_jump (done_label);
    1297        14592 :               goto do_error_label;
    1298              :             }
    1299              : 
    1300            0 :           delete_insns_since (last);
    1301              :         }
    1302              : 
    1303              :       /* Compute the operation.  On RTL level, the addition is always
    1304              :          unsigned.  */
    1305         1658 :       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1306              :                           op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1307          829 :       rtx tem = op0;
    1308              :       /* For PLUS_EXPR, the operation is commutative, so we can pick
    1309              :          operand to compare against.  For prec <= BITS_PER_WORD, I think
    1310              :          preferring REG operand is better over CONST_INT, because
    1311              :          the CONST_INT might enlarge the instruction or CSE would need
    1312              :          to figure out we'd already loaded it into a register before.
    1313              :          For prec > BITS_PER_WORD, I think CONST_INT might be more beneficial,
    1314              :          as then the multi-word comparison can be perhaps simplified.  */
    1315          829 :       if (code == PLUS_EXPR
    1316            0 :           && (prec <= BITS_PER_WORD
    1317            0 :               ? (CONST_SCALAR_INT_P (op0) && REG_P (op1))
    1318            0 :               : CONST_SCALAR_INT_P (op1)))
    1319          829 :         tem = op1;
    1320         1658 :       do_compare_rtx_and_jump (res, tem, code == PLUS_EXPR ? GEU : LEU,
    1321              :                                true, mode, NULL_RTX, NULL, done_label,
    1322              :                                profile_probability::very_likely ());
    1323          829 :       goto do_error_label;
    1324              :     }
    1325              : 
    1326              :   /* s1 +- u2 -> sr  */
    1327        23703 :   if (!uns0_p && uns1_p && !unsr_p)
    1328              :     {
    1329              :       /* Compute the operation.  On RTL level, the addition is always
    1330              :          unsigned.  */
    1331         2514 :       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1332              :                           op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1333         2514 :       rtx tem = expand_binop (mode, add_optab,
    1334              :                               code == PLUS_EXPR ? res : op0, sgn,
    1335              :                               NULL_RTX, false, OPTAB_LIB_WIDEN);
    1336         1582 :       do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL,
    1337              :                                done_label, profile_probability::very_likely ());
    1338         1582 :       goto do_error_label;
    1339              :     }
    1340              : 
    1341              :   /* s1 + u2 -> ur  */
    1342        22121 :   if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
    1343              :     {
    1344         1691 :       op1 = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
    1345              :                           OPTAB_LIB_WIDEN);
    1346              :       /* As we've changed op1, we have to avoid using the value range
    1347              :          for the original argument.  */
    1348         1691 :       arg1 = error_mark_node;
    1349         1691 :       do_xor = true;
    1350         1691 :       goto do_signed;
    1351              :     }
    1352              : 
    1353              :   /* u1 - s2 -> ur  */
    1354        20430 :   if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
    1355              :     {
    1356          846 :       op0 = expand_binop (mode, add_optab, op0, sgn, NULL_RTX, false,
    1357              :                           OPTAB_LIB_WIDEN);
    1358              :       /* As we've changed op0, we have to avoid using the value range
    1359              :          for the original argument.  */
    1360          846 :       arg0 = error_mark_node;
    1361          846 :       do_xor = true;
    1362          846 :       goto do_signed;
    1363              :     }
    1364              : 
    1365              :   /* s1 - u2 -> ur  */
    1366        19584 :   if (code == MINUS_EXPR && !uns0_p && uns1_p && unsr_p)
    1367              :     {
    1368              :       /* Compute the operation.  On RTL level, the addition is always
    1369              :          unsigned.  */
    1370         1374 :       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
    1371              :                           OPTAB_LIB_WIDEN);
    1372         1374 :       int pos_neg = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
    1373         1374 :       if (pos_neg == 2)
    1374              :         /* If ARG0 is known to be always negative, this is always overflow.  */
    1375           39 :         emit_jump (do_error);
    1376         1335 :       else if (pos_neg == 3)
    1377              :         /* If ARG0 is not known to be always positive, check at runtime.  */
    1378         1335 :         do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX,
    1379              :                                  NULL, do_error, profile_probability::very_unlikely ());
    1380         1374 :       do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL,
    1381              :                                done_label, profile_probability::very_likely ());
    1382         1374 :       goto do_error_label;
    1383              :     }
    1384              : 
    1385              :   /* u1 - s2 -> sr  */
    1386        18210 :   if (code == MINUS_EXPR && uns0_p && !uns1_p && !unsr_p)
    1387              :     {
    1388              :       /* Compute the operation.  On RTL level, the addition is always
    1389              :          unsigned.  */
    1390          481 :       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
    1391              :                           OPTAB_LIB_WIDEN);
    1392          481 :       rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
    1393              :                               OPTAB_LIB_WIDEN);
    1394          481 :       do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL,
    1395              :                                done_label, profile_probability::very_likely ());
    1396          481 :       goto do_error_label;
    1397              :     }
    1398              : 
    1399              :   /* u1 + u2 -> sr  */
    1400        17729 :   if (code == PLUS_EXPR && uns0_p && uns1_p && !unsr_p)
    1401              :     {
    1402              :       /* Compute the operation.  On RTL level, the addition is always
    1403              :          unsigned.  */
    1404         1192 :       res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false,
    1405              :                           OPTAB_LIB_WIDEN);
    1406         1192 :       do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
    1407              :                                NULL, do_error, profile_probability::very_unlikely ());
    1408         1192 :       rtx tem = op1;
    1409              :       /* The operation is commutative, so we can pick operand to compare
    1410              :          against.  For prec <= BITS_PER_WORD, I think preferring REG operand
    1411              :          is better over CONST_INT, because the CONST_INT might enlarge the
    1412              :          instruction or CSE would need to figure out we'd already loaded it
    1413              :          into a register before.  For prec > BITS_PER_WORD, I think CONST_INT
    1414              :          might be more beneficial, as then the multi-word comparison can be
    1415              :          perhaps simplified.  */
    1416         1192 :       if (prec <= BITS_PER_WORD
    1417         1192 :           ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
    1418          408 :           : CONST_SCALAR_INT_P (op0))
    1419         1192 :         tem = op0;
    1420         1192 :       do_compare_rtx_and_jump (res, tem, GEU, true, mode, NULL_RTX, NULL,
    1421              :                                done_label, profile_probability::very_likely ());
    1422         1192 :       goto do_error_label;
    1423              :     }
    1424              : 
    1425              :   /* s1 +- s2 -> ur  */
    1426        16537 :   if (!uns0_p && !uns1_p && unsr_p)
    1427              :     {
    1428              :       /* Compute the operation.  On RTL level, the addition is always
    1429              :          unsigned.  */
    1430         3825 :       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1431              :                           op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1432         2589 :       int pos_neg = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
    1433         2589 :       if (code == PLUS_EXPR)
    1434              :         {
    1435         1353 :           int pos_neg0 = get_range_pos_neg (arg0,
    1436              :                                             currently_expanding_gimple_stmt);
    1437         1353 :           if (pos_neg0 != 3 && pos_neg == 3)
    1438              :             {
    1439              :               std::swap (op0, op1);
    1440              :               pos_neg = pos_neg0;
    1441              :             }
    1442              :         }
    1443         2589 :       rtx tem;
    1444         2589 :       if (pos_neg != 3)
    1445              :         {
    1446         1585 :           tem = expand_binop (mode, ((pos_neg == 1) ^ (code == MINUS_EXPR))
    1447              :                                     ? and_optab : ior_optab,
    1448              :                               op0, res, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1449          935 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL,
    1450              :                                    NULL, done_label, profile_probability::very_likely ());
    1451              :         }
    1452              :       else
    1453              :         {
    1454         1654 :           rtx_code_label *do_ior_label = gen_label_rtx ();
    1455         2357 :           do_compare_rtx_and_jump (op1, const0_rtx,
    1456              :                                    code == MINUS_EXPR ? GE : LT, false, mode,
    1457              :                                    NULL_RTX, NULL, do_ior_label,
    1458              :                                    profile_probability::even ());
    1459         1654 :           tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
    1460              :                               OPTAB_LIB_WIDEN);
    1461         1654 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    1462              :                                    NULL, done_label, profile_probability::very_likely ());
    1463         1654 :           emit_jump (do_error);
    1464         1654 :           emit_label (do_ior_label);
    1465         1654 :           tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
    1466              :                               OPTAB_LIB_WIDEN);
    1467         1654 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    1468              :                                    NULL, done_label, profile_probability::very_likely ());
    1469              :         }
    1470         2589 :       goto do_error_label;
    1471              :     }
    1472              : 
    1473              :   /* u1 - u2 -> sr  */
    1474        13948 :   if (code == MINUS_EXPR && uns0_p && uns1_p && !unsr_p)
    1475              :     {
    1476              :       /* Compute the operation.  On RTL level, the addition is always
    1477              :          unsigned.  */
    1478         1729 :       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
    1479              :                           OPTAB_LIB_WIDEN);
    1480         1729 :       rtx_code_label *op0_geu_op1 = gen_label_rtx ();
    1481         1729 :       do_compare_rtx_and_jump (op0, op1, GEU, true, mode, NULL_RTX, NULL,
    1482              :                                op0_geu_op1, profile_probability::even ());
    1483         1729 :       do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
    1484              :                                NULL, done_label, profile_probability::very_likely ());
    1485         1729 :       emit_jump (do_error);
    1486         1729 :       emit_label (op0_geu_op1);
    1487         1729 :       do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
    1488              :                                NULL, done_label, profile_probability::very_likely ());
    1489         1729 :       goto do_error_label;
    1490              :     }
    1491              : 
    1492        12219 :   gcc_assert (!uns0_p && !uns1_p && !unsr_p);
    1493              : 
    1494              :   /* s1 +- s2 -> sr  */
    1495        12219 :  do_signed:
    1496        14756 :   {
    1497        21405 :     insn_code icode = optab_handler (code == PLUS_EXPR ? addv4_optab
    1498              :                                      : subv4_optab, mode);
    1499        14756 :     if (icode != CODE_FOR_nothing)
    1500              :       {
    1501        14756 :         class expand_operand ops[4];
    1502        14756 :         rtx_insn *last = get_last_insn ();
    1503              : 
    1504        14756 :         res = gen_reg_rtx (mode);
    1505        14756 :         create_output_operand (&ops[0], res, mode);
    1506        14756 :         create_input_operand (&ops[1], op0, mode);
    1507        14756 :         create_input_operand (&ops[2], op1, mode);
    1508        14756 :         create_fixed_operand (&ops[3], do_error);
    1509        14756 :         if (maybe_expand_insn (icode, 4, ops))
    1510              :           {
    1511        14756 :             last = get_last_insn ();
    1512        14756 :             if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    1513         9703 :                 && JUMP_P (last)
    1514         9703 :                 && any_condjump_p (last)
    1515        24459 :                 && !find_reg_note (last, REG_BR_PROB, 0))
    1516         9703 :               add_reg_br_prob_note (last,
    1517              :                                     profile_probability::very_unlikely ());
    1518        14756 :             emit_jump (done_label);
    1519        14756 :             goto do_error_label;
    1520              :           }
    1521              : 
    1522            0 :         delete_insns_since (last);
    1523              :       }
    1524              : 
    1525              :     /* Compute the operation.  On RTL level, the addition is always
    1526              :        unsigned.  */
    1527            0 :     res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1528              :                         op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1529              : 
    1530              :     /* If we can prove that one of the arguments (for MINUS_EXPR only
    1531              :        the second operand, as subtraction is not commutative) is always
    1532              :        non-negative or always negative, we can do just one comparison
    1533              :        and conditional jump.  */
    1534            0 :     int pos_neg = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
    1535            0 :     if (code == PLUS_EXPR)
    1536              :       {
    1537            0 :         int pos_neg0 = get_range_pos_neg (arg0,
    1538              :                                           currently_expanding_gimple_stmt);
    1539            0 :         if (pos_neg0 != 3 && pos_neg == 3)
    1540              :           {
    1541              :             std::swap (op0, op1);
    1542              :             pos_neg = pos_neg0;
    1543              :           }
    1544              :       }
    1545              : 
    1546              :     /* Addition overflows if and only if the two operands have the same sign,
    1547              :        and the result has the opposite sign.  Subtraction overflows if and
    1548              :        only if the two operands have opposite sign, and the subtrahend has
    1549              :        the same sign as the result.  Here 0 is counted as positive.  */
    1550            0 :     if (pos_neg == 3)
    1551              :       {
    1552              :         /* Compute op0 ^ op1 (operands have opposite sign).  */
    1553            0 :         rtx op_xor = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
    1554              :                                    OPTAB_LIB_WIDEN);
    1555              : 
    1556              :         /* Compute res ^ op1 (result and 2nd operand have opposite sign).  */
    1557            0 :         rtx res_xor = expand_binop (mode, xor_optab, res, op1, NULL_RTX, false,
    1558              :                                     OPTAB_LIB_WIDEN);
    1559              : 
    1560            0 :         rtx tem;
    1561            0 :         if (code == PLUS_EXPR)
    1562              :           {
    1563              :             /* Compute (res ^ op1) & ~(op0 ^ op1).  */
    1564            0 :             tem = expand_unop (mode, one_cmpl_optab, op_xor, NULL_RTX, false);
    1565            0 :             tem = expand_binop (mode, and_optab, res_xor, tem, NULL_RTX, false,
    1566              :                                 OPTAB_LIB_WIDEN);
    1567              :           }
    1568              :         else
    1569              :           {
    1570              :             /* Compute (op0 ^ op1) & ~(res ^ op1).  */
    1571            0 :             tem = expand_unop (mode, one_cmpl_optab, res_xor, NULL_RTX, false);
    1572            0 :             tem = expand_binop (mode, and_optab, op_xor, tem, NULL_RTX, false,
    1573              :                                 OPTAB_LIB_WIDEN);
    1574              :           }
    1575              : 
    1576              :         /* No overflow if the result has bit sign cleared.  */
    1577            0 :         do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    1578              :                                  NULL, done_label, profile_probability::very_likely ());
    1579              :       }
    1580              : 
    1581              :     /* Compare the result of the operation with the first operand.
    1582              :        No overflow for addition if second operand is positive and result
    1583              :        is larger or second operand is negative and result is smaller.
    1584              :        Likewise for subtraction with sign of second operand flipped.  */
    1585              :     else
    1586            0 :       do_compare_rtx_and_jump (res, op0,
    1587            0 :                                (pos_neg == 1) ^ (code == MINUS_EXPR) ? GE : LE,
    1588              :                                false, mode, NULL_RTX, NULL, done_label,
    1589              :                                profile_probability::very_likely ());
    1590              :   }
    1591              : 
    1592        39124 :  do_error_label:
    1593        39124 :   emit_label (do_error);
    1594        39124 :   if (is_ubsan)
    1595              :     {
    1596              :       /* Expand the ubsan builtin call.  */
    1597         3391 :       push_temp_slots ();
    1598         3391 :       fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
    1599              :                                          arg0, arg1, datap);
    1600         3391 :       expand_normal (fn);
    1601         3391 :       pop_temp_slots ();
    1602         3391 :       do_pending_stack_adjust ();
    1603              :     }
    1604        35733 :   else if (lhs)
    1605        35733 :     expand_arith_set_overflow (lhs, target);
    1606              : 
    1607              :   /* We're done.  */
    1608        39124 :   emit_label (done_label);
    1609              : 
    1610        39124 :   if (lhs)
    1611              :     {
    1612        38596 :       if (is_ubsan)
    1613         2863 :         expand_ubsan_result_store (lhs, target, mode, res, do_error);
    1614              :       else
    1615              :         {
    1616        35733 :           if (do_xor)
    1617         2537 :             res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
    1618              :                                 OPTAB_LIB_WIDEN);
    1619              : 
    1620        35733 :           expand_arith_overflow_result_store (lhs, target, mode, res);
    1621              :         }
    1622              :     }
    1623        39124 : }
    1624              : 
    1625              : /* Add negate overflow checking to the statement STMT.  */
    1626              : 
    1627              : static void
    1628         1052 : expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan,
    1629              :                      tree *datap)
    1630              : {
    1631         1052 :   rtx res, op1;
    1632         1052 :   tree fn;
    1633         1052 :   rtx_code_label *done_label, *do_error;
    1634         1052 :   rtx target = NULL_RTX;
    1635              : 
    1636         1052 :   done_label = gen_label_rtx ();
    1637         1052 :   do_error = gen_label_rtx ();
    1638              : 
    1639         1052 :   do_pending_stack_adjust ();
    1640         1052 :   op1 = expand_normal (arg1);
    1641              : 
    1642         1052 :   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg1));
    1643         1052 :   if (lhs)
    1644              :     {
    1645          848 :       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    1646          848 :       if (!is_ubsan)
    1647          402 :         write_complex_part (target, const0_rtx, true, false);
    1648              :     }
    1649              : 
    1650         1052 :   enum insn_code icode = optab_handler (negv3_optab, mode);
    1651         1052 :   if (icode != CODE_FOR_nothing)
    1652              :     {
    1653          974 :       class expand_operand ops[3];
    1654          974 :       rtx_insn *last = get_last_insn ();
    1655              : 
    1656          974 :       res = gen_reg_rtx (mode);
    1657          974 :       create_output_operand (&ops[0], res, mode);
    1658          974 :       create_input_operand (&ops[1], op1, mode);
    1659          974 :       create_fixed_operand (&ops[2], do_error);
    1660          974 :       if (maybe_expand_insn (icode, 3, ops))
    1661              :         {
    1662          974 :           last = get_last_insn ();
    1663          974 :           if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    1664          685 :               && JUMP_P (last)
    1665          685 :               && any_condjump_p (last)
    1666         1659 :               && !find_reg_note (last, REG_BR_PROB, 0))
    1667          685 :             add_reg_br_prob_note (last,
    1668              :                                   profile_probability::very_unlikely ());
    1669          974 :           emit_jump (done_label);
    1670              :         }
    1671              :       else
    1672              :         {
    1673            0 :           delete_insns_since (last);
    1674            0 :           icode = CODE_FOR_nothing;
    1675              :         }
    1676              :     }
    1677              : 
    1678          974 :   if (icode == CODE_FOR_nothing)
    1679              :     {
    1680              :       /* Compute the operation.  On RTL level, the addition is always
    1681              :          unsigned.  */
    1682           78 :       res = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
    1683              : 
    1684              :       /* Compare the operand with the most negative value.  */
    1685           78 :       rtx minv = expand_normal (TYPE_MIN_VALUE (TREE_TYPE (arg1)));
    1686           78 :       do_compare_rtx_and_jump (op1, minv, NE, true, mode, NULL_RTX, NULL,
    1687              :                                done_label, profile_probability::very_likely ());
    1688              :     }
    1689              : 
    1690         1052 :   emit_label (do_error);
    1691         1052 :   if (is_ubsan)
    1692              :     {
    1693              :       /* Expand the ubsan builtin call.  */
    1694          650 :       push_temp_slots ();
    1695          650 :       fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
    1696              :                                          arg1, NULL_TREE, datap);
    1697          650 :       expand_normal (fn);
    1698          650 :       pop_temp_slots ();
    1699          650 :       do_pending_stack_adjust ();
    1700              :     }
    1701          402 :   else if (lhs)
    1702          402 :     expand_arith_set_overflow (lhs, target);
    1703              : 
    1704              :   /* We're done.  */
    1705         1052 :   emit_label (done_label);
    1706              : 
    1707         1052 :   if (lhs)
    1708              :     {
    1709          848 :       if (is_ubsan)
    1710          446 :         expand_ubsan_result_store (lhs, target, mode, res, do_error);
    1711              :       else
    1712          402 :         expand_arith_overflow_result_store (lhs, target, mode, res);
    1713              :     }
    1714         1052 : }
    1715              : 
    1716              : /* Return true if UNS WIDEN_MULT_EXPR with result mode WMODE and operand
    1717              :    mode MODE can be expanded without using a libcall.  */
    1718              : 
    1719              : static bool
    1720            0 : can_widen_mult_without_libcall (scalar_int_mode wmode, scalar_int_mode mode,
    1721              :                                 rtx op0, rtx op1, bool uns)
    1722              : {
    1723            0 :   if (find_widening_optab_handler (umul_widen_optab, wmode, mode)
    1724              :       != CODE_FOR_nothing)
    1725              :     return true;
    1726              : 
    1727            0 :   if (find_widening_optab_handler (smul_widen_optab, wmode, mode)
    1728              :       != CODE_FOR_nothing)
    1729              :     return true;
    1730              : 
    1731            0 :   rtx_insn *last = get_last_insn ();
    1732            0 :   if (CONSTANT_P (op0))
    1733            0 :     op0 = convert_modes (wmode, mode, op0, uns);
    1734              :   else
    1735            0 :     op0 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 1);
    1736            0 :   if (CONSTANT_P (op1))
    1737            0 :     op1 = convert_modes (wmode, mode, op1, uns);
    1738              :   else
    1739            0 :     op1 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 2);
    1740            0 :   rtx ret = expand_mult (wmode, op0, op1, NULL_RTX, uns, true);
    1741            0 :   delete_insns_since (last);
    1742            0 :   return ret != NULL_RTX;
    1743              : }
    1744              : 
    1745              : /* Add mul overflow checking to the statement STMT.  */
    1746              : 
    1747              : static void
    1748        18898 : expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
    1749              :                      bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan,
    1750              :                      tree *datap)
    1751              : {
    1752        18898 :   rtx res, op0, op1;
    1753        18898 :   tree fn, type, orig_arg0 = arg0, orig_arg1 = arg1;
    1754        18898 :   rtx_code_label *done_label, *do_error;
    1755        18898 :   rtx target = NULL_RTX;
    1756        18898 :   signop sign;
    1757        18898 :   enum insn_code icode;
    1758        18898 :   int save_flag_trapv = flag_trapv;
    1759              : 
    1760              :   /* We don't want any __mulv?i3 etc. calls from the expansion of
    1761              :      these internal functions, so disable -ftrapv temporarily.  */
    1762        18898 :   flag_trapv = 0;
    1763        18898 :   done_label = gen_label_rtx ();
    1764        18898 :   do_error = gen_label_rtx ();
    1765              : 
    1766        18898 :   do_pending_stack_adjust ();
    1767              : 
    1768        18898 :   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
    1769              :   /* If the operand types don't have mode precision, extend them
    1770              :      to mode precision.  */
    1771        18898 :   if (TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
    1772              :     {
    1773          619 :       tree type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    1774              :                                                   uns0_p);
    1775          619 :       arg0 = fold_convert_loc (loc, type, arg0);
    1776              :     }
    1777        18898 :   if (TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
    1778              :     {
    1779          619 :       tree type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    1780              :                                                   uns1_p);
    1781          619 :       arg1 = fold_convert_loc (loc, type, arg1);
    1782              :     }
    1783              : 
    1784        18898 :   op0 = expand_normal (arg0);
    1785        18898 :   op1 = expand_normal (arg1);
    1786              : 
    1787        18898 :   bool uns = unsr_p;
    1788        18898 :   if (lhs)
    1789              :     {
    1790        18754 :       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    1791        18754 :       if (!is_ubsan)
    1792        17388 :         write_complex_part (target, const0_rtx, true, false);
    1793              :     }
    1794              : 
    1795        17532 :   if (is_ubsan)
    1796         1510 :     gcc_assert (!unsr_p && !uns0_p && !uns1_p);
    1797              : 
    1798              :   /* We assume both operands and result have the same precision
    1799              :      here (GET_MODE_BITSIZE (mode)), S stands for signed type
    1800              :      with that precision, U for unsigned type with that precision,
    1801              :      sgn for unsigned most significant bit in that precision.
    1802              :      s1 is signed first operand, u1 is unsigned first operand,
    1803              :      s2 is signed second operand, u2 is unsigned second operand,
    1804              :      sr is signed result, ur is unsigned result and the following
    1805              :      rules say how to compute result (which is always result of
    1806              :      the operands as if both were unsigned, cast to the right
    1807              :      signedness) and how to compute whether operation overflowed.
    1808              :      main_ovf (false) stands for jump on signed multiplication
    1809              :      overflow or the main algorithm with uns == false.
    1810              :      main_ovf (true) stands for jump on unsigned multiplication
    1811              :      overflow or the main algorithm with uns == true.
    1812              : 
    1813              :      s1 * s2 -> sr
    1814              :         res = (S) ((U) s1 * (U) s2)
    1815              :         ovf = main_ovf (false)
    1816              :      u1 * u2 -> ur
    1817              :         res = u1 * u2
    1818              :         ovf = main_ovf (true)
    1819              :      s1 * u2 -> ur
    1820              :         res = (U) s1 * u2
    1821              :         ovf = (s1 < 0 && u2) || main_ovf (true)
    1822              :      u1 * u2 -> sr
    1823              :         res = (S) (u1 * u2)
    1824              :         ovf = res < 0 || main_ovf (true)
    1825              :      s1 * u2 -> sr
    1826              :         res = (S) ((U) s1 * u2)
    1827              :         ovf = (S) u2 >= 0 ? main_ovf (false)
    1828              :                           : (s1 != 0 && (s1 != -1 || u2 != (U) res))
    1829              :      s1 * s2 -> ur
    1830              :         t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
    1831              :         t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
    1832              :         res = t1 * t2
    1833              :         ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true)  */
    1834              : 
    1835        18898 :   if (uns0_p && !uns1_p)
    1836              :     {
    1837              :       /* Multiplication is commutative, if operand signedness differs,
    1838              :          canonicalize to the first operand being signed and second
    1839              :          unsigned to simplify following code.  */
    1840         1558 :       std::swap (op0, op1);
    1841         1558 :       std::swap (arg0, arg1);
    1842         1558 :       uns0_p = false;
    1843         1558 :       uns1_p = true;
    1844              :     }
    1845              : 
    1846        18898 :   int pos_neg0 = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
    1847        18898 :   int pos_neg1 = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
    1848              : 
    1849              :   /* s1 * u2 -> ur  */
    1850        18898 :   if (!uns0_p && uns1_p && unsr_p)
    1851              :     {
    1852         2254 :       switch (pos_neg0)
    1853              :         {
    1854            0 :         case 1:
    1855              :           /* If s1 is non-negative, just perform normal u1 * u2 -> ur.  */
    1856         1821 :           goto do_main;
    1857          328 :         case 2:
    1858              :           /* If s1 is negative, avoid the main code, just multiply and
    1859              :              signal overflow if op1 is not 0.  */
    1860          328 :           struct separate_ops ops;
    1861          328 :           ops.code = MULT_EXPR;
    1862          328 :           ops.type = TREE_TYPE (arg1);
    1863          328 :           ops.op0 = make_tree (ops.type, op0);
    1864          328 :           ops.op1 = make_tree (ops.type, op1);
    1865          328 :           ops.op2 = NULL_TREE;
    1866          328 :           ops.location = loc;
    1867          328 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1868          328 :           do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
    1869              :                                    NULL, done_label, profile_probability::very_likely ());
    1870          433 :           goto do_error_label;
    1871         1926 :         case 3:
    1872         3852 :           if (get_min_precision (arg1, UNSIGNED)
    1873         1926 :               + get_min_precision (arg0, SIGNED) <= GET_MODE_PRECISION (mode))
    1874              :             {
    1875              :               /* If the first operand is sign extended from narrower type, the
    1876              :                  second operand is zero extended from narrower type and
    1877              :                  the sum of the two precisions is smaller or equal to the
    1878              :                  result precision: if the first argument is at runtime
    1879              :                  non-negative, maximum result will be 0x7e81 or 0x7f..fe80..01
    1880              :                  and there will be no overflow, if the first argument is
    1881              :                  negative and the second argument zero, the result will be
    1882              :                  0 and there will be no overflow, if the first argument is
    1883              :                  negative and the second argument positive, the result when
    1884              :                  treated as signed will be negative (minimum -0x7f80 or
    1885              :                  -0x7f..f80..0) there will be always overflow.  So, do
    1886              :                  res = (U) (s1 * u2)
    1887              :                  ovf = (S) res < 0  */
    1888          105 :               struct separate_ops ops;
    1889          105 :               ops.code = MULT_EXPR;
    1890          105 :               ops.type
    1891          105 :                 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    1892              :                                                   1);
    1893          105 :               ops.op0 = make_tree (ops.type, op0);
    1894          105 :               ops.op1 = make_tree (ops.type, op1);
    1895          105 :               ops.op2 = NULL_TREE;
    1896          105 :               ops.location = loc;
    1897          105 :               res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1898          105 :               do_compare_rtx_and_jump (res, const0_rtx, GE, false,
    1899              :                                        mode, NULL_RTX, NULL, done_label,
    1900              :                                        profile_probability::very_likely ());
    1901          105 :               goto do_error_label;
    1902              :             }
    1903         1821 :           rtx_code_label *do_main_label;
    1904         1821 :           do_main_label = gen_label_rtx ();
    1905         1821 :           do_compare_rtx_and_jump (op0, const0_rtx, GE, false, mode, NULL_RTX,
    1906              :                                    NULL, do_main_label, profile_probability::very_likely ());
    1907         1821 :           do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
    1908              :                                    NULL, do_main_label, profile_probability::very_likely ());
    1909         1821 :           expand_arith_set_overflow (lhs, target);
    1910         1821 :           emit_label (do_main_label);
    1911         1821 :           goto do_main;
    1912            0 :         default:
    1913            0 :           gcc_unreachable ();
    1914              :         }
    1915              :     }
    1916              : 
    1917              :   /* u1 * u2 -> sr  */
    1918        16644 :   if (uns0_p && uns1_p && !unsr_p)
    1919              :     {
    1920         1369 :       if ((pos_neg0 | pos_neg1) == 1)
    1921              :         {
    1922              :           /* If both arguments are zero extended from narrower types,
    1923              :              the MSB will be clear on both and so we can pretend it is
    1924              :              a normal s1 * s2 -> sr multiplication.  */
    1925              :           uns0_p = false;
    1926              :           uns1_p = false;
    1927              :         }
    1928              :       else
    1929          957 :         uns = true;
    1930              :       /* Rest of handling of this case after res is computed.  */
    1931         1369 :       goto do_main;
    1932              :     }
    1933              : 
    1934              :   /* s1 * u2 -> sr  */
    1935        15275 :   if (!uns0_p && uns1_p && !unsr_p)
    1936              :     {
    1937         1788 :       switch (pos_neg1)
    1938              :         {
    1939           66 :         case 1:
    1940         1339 :           goto do_main;
    1941          449 :         case 2:
    1942              :           /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
    1943              :              avoid the main code, just multiply and signal overflow
    1944              :              unless 0 * u2 or -1 * ((U) Smin).  */
    1945          449 :           struct separate_ops ops;
    1946          449 :           ops.code = MULT_EXPR;
    1947          449 :           ops.type = TREE_TYPE (arg1);
    1948          449 :           ops.op0 = make_tree (ops.type, op0);
    1949          449 :           ops.op1 = make_tree (ops.type, op1);
    1950          449 :           ops.op2 = NULL_TREE;
    1951          449 :           ops.location = loc;
    1952          449 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1953          449 :           do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
    1954              :                                    NULL, done_label, profile_probability::very_likely ());
    1955          449 :           do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
    1956              :                                    NULL, do_error, profile_probability::very_unlikely ());
    1957          449 :           int prec;
    1958          449 :           prec = GET_MODE_PRECISION (mode);
    1959          449 :           rtx sgn;
    1960          449 :           sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
    1961          449 :           do_compare_rtx_and_jump (op1, sgn, EQ, true, mode, NULL_RTX,
    1962              :                                    NULL, done_label, profile_probability::very_likely ());
    1963          449 :           goto do_error_label;
    1964         1273 :         case 3:
    1965              :           /* Rest of handling of this case after res is computed.  */
    1966         1273 :           goto do_main;
    1967            0 :         default:
    1968            0 :           gcc_unreachable ();
    1969              :         }
    1970              :     }
    1971              : 
    1972              :   /* s1 * s2 -> ur  */
    1973        13487 :   if (!uns0_p && !uns1_p && unsr_p)
    1974              :     {
    1975         2329 :       rtx tem;
    1976         2329 :       switch (pos_neg0 | pos_neg1)
    1977              :         {
    1978            0 :         case 1: /* Both operands known to be non-negative.  */
    1979            0 :           goto do_main;
    1980           12 :         case 2: /* Both operands known to be negative.  */
    1981           12 :           op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
    1982           12 :           op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
    1983              :           /* Avoid looking at arg0/arg1 ranges, as we've changed
    1984              :              the arguments.  */
    1985           12 :           arg0 = error_mark_node;
    1986           12 :           arg1 = error_mark_node;
    1987           12 :           goto do_main;
    1988         2317 :         case 3:
    1989         2317 :           if ((pos_neg0 ^ pos_neg1) == 3)
    1990              :             {
    1991              :               /* If one operand is known to be negative and the other
    1992              :                  non-negative, this overflows always, unless the non-negative
    1993              :                  one is 0.  Just do normal multiply and set overflow
    1994              :                  unless one of the operands is 0.  */
    1995            0 :               struct separate_ops ops;
    1996            0 :               ops.code = MULT_EXPR;
    1997            0 :               ops.type
    1998            0 :                 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    1999              :                                                   1);
    2000            0 :               ops.op0 = make_tree (ops.type, op0);
    2001            0 :               ops.op1 = make_tree (ops.type, op1);
    2002            0 :               ops.op2 = NULL_TREE;
    2003            0 :               ops.location = loc;
    2004            0 :               res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2005            0 :               do_compare_rtx_and_jump (pos_neg0 == 1 ? op0 : op1, const0_rtx, EQ,
    2006              :                                        true, mode, NULL_RTX, NULL, done_label,
    2007              :                                        profile_probability::very_likely ());
    2008            0 :               goto do_error_label;
    2009              :             }
    2010         4634 :           if (get_min_precision (arg0, SIGNED)
    2011         2317 :               + get_min_precision (arg1, SIGNED) <= GET_MODE_PRECISION (mode))
    2012              :             {
    2013              :               /* If both operands are sign extended from narrower types and
    2014              :                  the sum of the two precisions is smaller or equal to the
    2015              :                  result precision: if both arguments are at runtime
    2016              :                  non-negative, maximum result will be 0x3f01 or 0x3f..f0..01
    2017              :                  and there will be no overflow, if both arguments are negative,
    2018              :                  maximum result will be 0x40..00 and there will be no overflow
    2019              :                  either, if one argument is positive and the other argument
    2020              :                  negative, the result when treated as signed will be negative
    2021              :                  and there will be always overflow, and if one argument is
    2022              :                  zero and the other negative the result will be zero and no
    2023              :                  overflow.  So, do
    2024              :                  res = (U) (s1 * s2)
    2025              :                  ovf = (S) res < 0  */
    2026          220 :               struct separate_ops ops;
    2027          220 :               ops.code = MULT_EXPR;
    2028          220 :               ops.type
    2029          220 :                 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    2030              :                                                   1);
    2031          220 :               ops.op0 = make_tree (ops.type, op0);
    2032          220 :               ops.op1 = make_tree (ops.type, op1);
    2033          220 :               ops.op2 = NULL_TREE;
    2034          220 :               ops.location = loc;
    2035          220 :               res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2036          220 :               do_compare_rtx_and_jump (res, const0_rtx, GE, false,
    2037              :                                        mode, NULL_RTX, NULL, done_label,
    2038              :                                        profile_probability::very_likely ());
    2039          220 :               goto do_error_label;
    2040              :             }
    2041              :           /* The general case, do all the needed comparisons at runtime.  */
    2042         2097 :           rtx_code_label *do_main_label, *after_negate_label;
    2043         2097 :           rtx rop0, rop1;
    2044         2097 :           rop0 = gen_reg_rtx (mode);
    2045         2097 :           rop1 = gen_reg_rtx (mode);
    2046         2097 :           emit_move_insn (rop0, op0);
    2047         2097 :           emit_move_insn (rop1, op1);
    2048         2097 :           op0 = rop0;
    2049         2097 :           op1 = rop1;
    2050         2097 :           do_main_label = gen_label_rtx ();
    2051         2097 :           after_negate_label = gen_label_rtx ();
    2052         2097 :           tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
    2053              :                               OPTAB_LIB_WIDEN);
    2054         2097 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    2055              :                                    NULL, after_negate_label, profile_probability::very_likely ());
    2056              :           /* Both arguments negative here, negate them and continue with
    2057              :              normal unsigned overflow checking multiplication.  */
    2058         2097 :           emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
    2059              :                                             NULL_RTX, false));
    2060         2097 :           emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
    2061              :                                             NULL_RTX, false));
    2062              :           /* Avoid looking at arg0/arg1 ranges, as we might have changed
    2063              :              the arguments.  */
    2064         2097 :           arg0 = error_mark_node;
    2065         2097 :           arg1 = error_mark_node;
    2066         2097 :           emit_jump (do_main_label);
    2067         2097 :           emit_label (after_negate_label);
    2068         2097 :           tem = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
    2069              :                               OPTAB_LIB_WIDEN);
    2070         2097 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    2071              :                                    NULL, do_main_label,
    2072              :                                    profile_probability::very_likely ());
    2073              :           /* One argument is negative here, the other positive.  This
    2074              :              overflows always, unless one of the arguments is 0.  But
    2075              :              if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
    2076              :              is, thus we can keep do_main code oring in overflow as is.  */
    2077         2097 :           if (pos_neg0 != 2)
    2078         2097 :             do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
    2079              :                                      NULL, do_main_label,
    2080              :                                      profile_probability::very_unlikely ());
    2081         2097 :           if (pos_neg1 != 2)
    2082         1080 :             do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
    2083              :                                      NULL, do_main_label,
    2084              :                                      profile_probability::very_unlikely ());
    2085         2097 :           expand_arith_set_overflow (lhs, target);
    2086         2097 :           emit_label (do_main_label);
    2087         2097 :           goto do_main;
    2088            0 :         default:
    2089            0 :           gcc_unreachable ();
    2090              :         }
    2091              :     }
    2092              : 
    2093        11158 :  do_main:
    2094        17796 :   type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
    2095        17796 :   sign = uns ? UNSIGNED : SIGNED;
    2096        17796 :   icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
    2097        17796 :   if (uns
    2098        10458 :       && (integer_pow2p (arg0) || integer_pow2p (arg1))
    2099        18663 :       && (optimize_insn_for_speed_p () || icode == CODE_FOR_nothing))
    2100              :     {
    2101              :       /* Optimize unsigned multiplication by power of 2 constant
    2102              :          using 2 shifts, one for result, one to extract the shifted
    2103              :          out bits to see if they are all zero.
    2104              :          Don't do this if optimizing for size and we have umulv4_optab,
    2105              :          in that case assume multiplication will be shorter.
    2106              :          This is heuristics based on the single target that provides
    2107              :          umulv4 right now (i?86/x86_64), if further targets add it, this
    2108              :          might need to be revisited.
    2109              :          Cases where both operands are constant should be folded already
    2110              :          during GIMPLE, and cases where one operand is constant but not
    2111              :          power of 2 are questionable, either the WIDEN_MULT_EXPR case
    2112              :          below can be done without multiplication, just by shifts and adds,
    2113              :          or we'd need to divide the result (and hope it actually doesn't
    2114              :          really divide nor multiply) and compare the result of the division
    2115              :          with the original operand.  */
    2116          865 :       rtx opn0 = op0;
    2117          865 :       rtx opn1 = op1;
    2118          865 :       tree argn0 = arg0;
    2119          865 :       tree argn1 = arg1;
    2120          865 :       if (integer_pow2p (arg0))
    2121              :         {
    2122            0 :           std::swap (opn0, opn1);
    2123            0 :           std::swap (argn0, argn1);
    2124              :         }
    2125          865 :       int cnt = tree_log2 (argn1);
    2126          865 :       if (cnt >= 0 && cnt < GET_MODE_PRECISION (mode))
    2127              :         {
    2128          865 :           rtx upper = const0_rtx;
    2129          865 :           res = expand_shift (LSHIFT_EXPR, mode, opn0, cnt, NULL_RTX, uns);
    2130          865 :           if (cnt != 0)
    2131          693 :             upper = expand_shift (RSHIFT_EXPR, mode, opn0,
    2132          693 :                                   GET_MODE_PRECISION (mode) - cnt,
    2133              :                                   NULL_RTX, uns);
    2134          865 :           do_compare_rtx_and_jump (upper, const0_rtx, EQ, true, mode,
    2135              :                                    NULL_RTX, NULL, done_label,
    2136              :                                    profile_probability::very_likely ());
    2137          865 :           goto do_error_label;
    2138              :         }
    2139              :     }
    2140        16931 :   if (icode != CODE_FOR_nothing)
    2141              :     {
    2142        13832 :       class expand_operand ops[4];
    2143        13832 :       rtx_insn *last = get_last_insn ();
    2144              : 
    2145        13832 :       res = gen_reg_rtx (mode);
    2146        13832 :       create_output_operand (&ops[0], res, mode);
    2147        13832 :       create_input_operand (&ops[1], op0, mode);
    2148        13832 :       create_input_operand (&ops[2], op1, mode);
    2149        13832 :       create_fixed_operand (&ops[3], do_error);
    2150        13832 :       if (maybe_expand_insn (icode, 4, ops))
    2151              :         {
    2152        13832 :           last = get_last_insn ();
    2153        13832 :           if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    2154         9154 :               && JUMP_P (last)
    2155         9154 :               && any_condjump_p (last)
    2156        22986 :               && !find_reg_note (last, REG_BR_PROB, 0))
    2157         9154 :             add_reg_br_prob_note (last,
    2158              :                                   profile_probability::very_unlikely ());
    2159        13832 :           emit_jump (done_label);
    2160              :         }
    2161              :       else
    2162              :         {
    2163            0 :           delete_insns_since (last);
    2164            0 :           icode = CODE_FOR_nothing;
    2165              :         }
    2166              :     }
    2167              : 
    2168            0 :   if (icode == CODE_FOR_nothing)
    2169              :     {
    2170         3099 :       struct separate_ops ops;
    2171         3099 :       int prec = GET_MODE_PRECISION (mode);
    2172         3099 :       scalar_int_mode hmode, wmode;
    2173         3099 :       ops.op0 = make_tree (type, op0);
    2174         3099 :       ops.op1 = make_tree (type, op1);
    2175         3099 :       ops.op2 = NULL_TREE;
    2176         3099 :       ops.location = loc;
    2177              : 
    2178              :       /* Optimize unsigned overflow check where we don't use the
    2179              :          multiplication result, just whether overflow happened.
    2180              :          If we can do MULT_HIGHPART_EXPR, that followed by
    2181              :          comparison of the result against zero is cheapest.
    2182              :          We'll still compute res, but it should be DCEd later.  */
    2183         3099 :       use_operand_p use;
    2184         3099 :       gimple *use_stmt;
    2185         3099 :       if (!is_ubsan
    2186         3099 :           && lhs
    2187         3079 :           && uns
    2188         1973 :           && !(uns0_p && uns1_p && !unsr_p)
    2189         1692 :           && can_mult_highpart_p (mode, uns) == 1
    2190            0 :           && single_imm_use (lhs, &use, &use_stmt)
    2191            0 :           && is_gimple_assign (use_stmt)
    2192         3099 :           && gimple_assign_rhs_code (use_stmt) == IMAGPART_EXPR)
    2193            0 :         goto highpart;
    2194              : 
    2195         3099 :       if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
    2196         3099 :           && targetm.scalar_mode_supported_p (wmode)
    2197            0 :           && can_widen_mult_without_libcall (wmode, mode, op0, op1, uns))
    2198              :         {
    2199            0 :         twoxwider:
    2200            0 :           ops.code = WIDEN_MULT_EXPR;
    2201            0 :           ops.type
    2202            0 :             = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
    2203              : 
    2204            0 :           res = expand_expr_real_2 (&ops, NULL_RTX, wmode, EXPAND_NORMAL);
    2205            0 :           rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
    2206              :                                      NULL_RTX, uns);
    2207            0 :           hipart = convert_modes (mode, wmode, hipart, uns);
    2208            0 :           res = convert_modes (mode, wmode, res, uns);
    2209            0 :           if (uns)
    2210              :             /* For the unsigned multiplication, there was overflow if
    2211              :                HIPART is non-zero.  */
    2212            0 :             do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
    2213              :                                      NULL_RTX, NULL, done_label,
    2214              :                                      profile_probability::very_likely ());
    2215              :           else
    2216              :             {
    2217              :               /* RES is used more than once, place it in a pseudo.  */
    2218            0 :               res = force_reg (mode, res);
    2219              : 
    2220            0 :               rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
    2221              :                                           NULL_RTX, 0);
    2222              :               /* RES is low half of the double width result, HIPART
    2223              :                  the high half.  There was overflow if
    2224              :                  HIPART is different from RES < 0 ? -1 : 0.  */
    2225            0 :               do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
    2226              :                                        NULL_RTX, NULL, done_label,
    2227              :                                        profile_probability::very_likely ());
    2228              :             }
    2229              :         }
    2230         3099 :       else if (can_mult_highpart_p (mode, uns) == 1)
    2231              :         {
    2232            0 :         highpart:
    2233            0 :           ops.code = MULT_HIGHPART_EXPR;
    2234            0 :           ops.type = type;
    2235              : 
    2236            0 :           rtx hipart = expand_expr_real_2 (&ops, NULL_RTX, mode,
    2237              :                                            EXPAND_NORMAL);
    2238            0 :           ops.code = MULT_EXPR;
    2239            0 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2240            0 :           if (uns)
    2241              :             /* For the unsigned multiplication, there was overflow if
    2242              :                HIPART is non-zero.  */
    2243            0 :             do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
    2244              :                                      NULL_RTX, NULL, done_label,
    2245              :                                      profile_probability::very_likely ());
    2246              :           else
    2247              :             {
    2248            0 :               rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
    2249              :                                           NULL_RTX, 0);
    2250              :               /* RES is low half of the double width result, HIPART
    2251              :                  the high half.  There was overflow if
    2252              :                  HIPART is different from RES < 0 ? -1 : 0.  */
    2253            0 :               do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
    2254              :                                        NULL_RTX, NULL, done_label,
    2255              :                                        profile_probability::very_likely ());
    2256              :             }
    2257              : 
    2258              :         }
    2259         3099 :       else if (int_mode_for_size (prec / 2, 1).exists (&hmode)
    2260         3099 :                && 2 * GET_MODE_PRECISION (hmode) == prec)
    2261              :         {
    2262         3099 :           rtx_code_label *large_op0 = gen_label_rtx ();
    2263         3099 :           rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
    2264         3099 :           rtx_code_label *one_small_one_large = gen_label_rtx ();
    2265         3099 :           rtx_code_label *both_ops_large = gen_label_rtx ();
    2266         3099 :           rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
    2267         1126 :           rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
    2268         3099 :           rtx_code_label *do_overflow = gen_label_rtx ();
    2269         3099 :           rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
    2270              : 
    2271         3099 :           unsigned int hprec = GET_MODE_PRECISION (hmode);
    2272         3099 :           rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
    2273              :                                       NULL_RTX, uns);
    2274         3099 :           hipart0 = convert_modes (hmode, mode, hipart0, uns);
    2275         3099 :           rtx lopart0 = convert_modes (hmode, mode, op0, uns);
    2276         3099 :           rtx signbit0 = const0_rtx;
    2277         3099 :           if (!uns)
    2278         1126 :             signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
    2279              :                                      NULL_RTX, 0);
    2280         3099 :           rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
    2281              :                                       NULL_RTX, uns);
    2282         3099 :           hipart1 = convert_modes (hmode, mode, hipart1, uns);
    2283         3099 :           rtx lopart1 = convert_modes (hmode, mode, op1, uns);
    2284         3099 :           rtx signbit1 = const0_rtx;
    2285         3099 :           if (!uns)
    2286         1126 :             signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
    2287              :                                      NULL_RTX, 0);
    2288              : 
    2289         3099 :           res = gen_reg_rtx (mode);
    2290              : 
    2291              :           /* True if op0 resp. op1 are known to be in the range of
    2292              :              halfstype.  */
    2293         3099 :           bool op0_small_p = false;
    2294         3099 :           bool op1_small_p = false;
    2295              :           /* True if op0 resp. op1 are known to have all zeros or all ones
    2296              :              in the upper half of bits, but are not known to be
    2297              :              op{0,1}_small_p.  */
    2298         3099 :           bool op0_medium_p = false;
    2299         3099 :           bool op1_medium_p = false;
    2300              :           /* -1 if op{0,1} is known to be negative, 0 if it is known to be
    2301              :              nonnegative, 1 if unknown.  */
    2302         3099 :           int op0_sign = 1;
    2303         3099 :           int op1_sign = 1;
    2304              : 
    2305         3099 :           if (pos_neg0 == 1)
    2306              :             op0_sign = 0;
    2307         2950 :           else if (pos_neg0 == 2)
    2308          188 :             op0_sign = -1;
    2309         3099 :           if (pos_neg1 == 1)
    2310              :             op1_sign = 0;
    2311         2002 :           else if (pos_neg1 == 2)
    2312          428 :             op1_sign = -1;
    2313              : 
    2314         3099 :           unsigned int mprec0 = prec;
    2315         3099 :           if (arg0 != error_mark_node)
    2316         2350 :             mprec0 = get_min_precision (arg0, sign);
    2317         3099 :           if (mprec0 <= hprec)
    2318              :             op0_small_p = true;
    2319         2923 :           else if (!uns && mprec0 <= hprec + 1)
    2320         3099 :             op0_medium_p = true;
    2321         3099 :           unsigned int mprec1 = prec;
    2322         3099 :           if (arg1 != error_mark_node)
    2323         2350 :             mprec1 = get_min_precision (arg1, sign);
    2324         3099 :           if (mprec1 <= hprec)
    2325              :             op1_small_p = true;
    2326         2582 :           else if (!uns && mprec1 <= hprec + 1)
    2327         3099 :             op1_medium_p = true;
    2328              : 
    2329         3099 :           int smaller_sign = 1;
    2330         3099 :           int larger_sign = 1;
    2331         3099 :           if (op0_small_p)
    2332              :             {
    2333              :               smaller_sign = op0_sign;
    2334              :               larger_sign = op1_sign;
    2335              :             }
    2336         2923 :           else if (op1_small_p)
    2337              :             {
    2338              :               smaller_sign = op1_sign;
    2339              :               larger_sign = op0_sign;
    2340              :             }
    2341         2406 :           else if (op0_sign == op1_sign)
    2342              :             {
    2343         1494 :               smaller_sign = op0_sign;
    2344         1494 :               larger_sign = op0_sign;
    2345              :             }
    2346              : 
    2347         2923 :           if (!op0_small_p)
    2348         2923 :             do_compare_rtx_and_jump (signbit0, hipart0, NE, true, hmode,
    2349              :                                      NULL_RTX, NULL, large_op0,
    2350              :                                      profile_probability::unlikely ());
    2351              : 
    2352         3099 :           if (!op1_small_p)
    2353         2582 :             do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
    2354              :                                      NULL_RTX, NULL, small_op0_large_op1,
    2355              :                                      profile_probability::unlikely ());
    2356              : 
    2357              :           /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
    2358              :              hmode to mode, the multiplication will never overflow.  We can
    2359              :              do just one hmode x hmode => mode widening multiplication.  */
    2360         3099 :           tree halfstype = build_nonstandard_integer_type (hprec, uns);
    2361         3099 :           ops.op0 = make_tree (halfstype, lopart0);
    2362         3099 :           ops.op1 = make_tree (halfstype, lopart1);
    2363         3099 :           ops.code = WIDEN_MULT_EXPR;
    2364         3099 :           ops.type = type;
    2365         3099 :           rtx thisres
    2366         3099 :             = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2367         3099 :           emit_move_insn (res, thisres);
    2368         3099 :           emit_jump (done_label);
    2369              : 
    2370         3099 :           emit_label (small_op0_large_op1);
    2371              : 
    2372              :           /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
    2373              :              but op1 is not, just swap the arguments and handle it as op1
    2374              :              sign/zero extended, op0 not.  */
    2375         3099 :           rtx larger = gen_reg_rtx (mode);
    2376         3099 :           rtx hipart = gen_reg_rtx (hmode);
    2377         3099 :           rtx lopart = gen_reg_rtx (hmode);
    2378         3099 :           emit_move_insn (larger, op1);
    2379         3099 :           emit_move_insn (hipart, hipart1);
    2380         3099 :           emit_move_insn (lopart, lopart0);
    2381         3099 :           emit_jump (one_small_one_large);
    2382              : 
    2383         3099 :           emit_label (large_op0);
    2384              : 
    2385         3099 :           if (!op1_small_p)
    2386         2582 :             do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
    2387              :                                      NULL_RTX, NULL, both_ops_large,
    2388              :                                      profile_probability::unlikely ());
    2389              : 
    2390              :           /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
    2391              :              but op0 is not, prepare larger, hipart and lopart pseudos and
    2392              :              handle it together with small_op0_large_op1.  */
    2393         3099 :           emit_move_insn (larger, op0);
    2394         3099 :           emit_move_insn (hipart, hipart0);
    2395         3099 :           emit_move_insn (lopart, lopart1);
    2396              : 
    2397         3099 :           emit_label (one_small_one_large);
    2398              : 
    2399              :           /* lopart is the low part of the operand that is sign extended
    2400              :              to mode, larger is the other operand, hipart is the
    2401              :              high part of larger and lopart0 and lopart1 are the low parts
    2402              :              of both operands.
    2403              :              We perform lopart0 * lopart1 and lopart * hipart widening
    2404              :              multiplications.  */
    2405         3099 :           tree halfutype = build_nonstandard_integer_type (hprec, 1);
    2406         3099 :           ops.op0 = make_tree (halfutype, lopart0);
    2407         3099 :           ops.op1 = make_tree (halfutype, lopart1);
    2408         3099 :           rtx lo0xlo1
    2409         3099 :             = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2410              : 
    2411         3099 :           ops.op0 = make_tree (halfutype, lopart);
    2412         3099 :           ops.op1 = make_tree (halfutype, hipart);
    2413         3099 :           rtx loxhi = gen_reg_rtx (mode);
    2414         3099 :           rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2415         3099 :           emit_move_insn (loxhi, tem);
    2416              : 
    2417         3099 :           if (!uns)
    2418              :             {
    2419              :               /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
    2420         1126 :               if (larger_sign == 0)
    2421           72 :                 emit_jump (after_hipart_neg);
    2422         1054 :               else if (larger_sign != -1)
    2423         1054 :                 do_compare_rtx_and_jump (hipart, const0_rtx, GE, false, hmode,
    2424              :                                          NULL_RTX, NULL, after_hipart_neg,
    2425              :                                          profile_probability::even ());
    2426              : 
    2427         1126 :               tem = convert_modes (mode, hmode, lopart, 1);
    2428         1126 :               tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
    2429         1126 :               tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
    2430              :                                          1, OPTAB_WIDEN);
    2431         1126 :               emit_move_insn (loxhi, tem);
    2432              : 
    2433         1126 :               emit_label (after_hipart_neg);
    2434              : 
    2435              :               /* if (lopart < 0) loxhi -= larger;  */
    2436         1126 :               if (smaller_sign == 0)
    2437          251 :                 emit_jump (after_lopart_neg);
    2438          875 :               else if (smaller_sign != -1)
    2439          705 :                 do_compare_rtx_and_jump (lopart, const0_rtx, GE, false, hmode,
    2440              :                                          NULL_RTX, NULL, after_lopart_neg,
    2441              :                                          profile_probability::even ());
    2442              : 
    2443         1126 :               tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
    2444              :                                          1, OPTAB_WIDEN);
    2445         1126 :               emit_move_insn (loxhi, tem);
    2446              : 
    2447         1126 :               emit_label (after_lopart_neg);
    2448              :             }
    2449              : 
    2450              :           /* loxhi += (uns) lo0xlo1 >> (bitsize / 2);  */
    2451         3099 :           tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
    2452         3099 :           tem = expand_simple_binop (mode, PLUS, loxhi, tem, NULL_RTX,
    2453              :                                      1, OPTAB_WIDEN);
    2454         3099 :           emit_move_insn (loxhi, tem);
    2455              : 
    2456              :           /* if (loxhi >> (bitsize / 2)
    2457              :                  == (hmode) loxhi >> (bitsize / 2 - 1))  (if !uns)
    2458              :              if (loxhi >> (bitsize / 2) == 0               (if uns).  */
    2459         3099 :           rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
    2460              :                                           NULL_RTX, 0);
    2461         3099 :           hipartloxhi = convert_modes (hmode, mode, hipartloxhi, 0);
    2462         3099 :           rtx signbitloxhi = const0_rtx;
    2463         3099 :           if (!uns)
    2464         1126 :             signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
    2465              :                                          convert_modes (hmode, mode,
    2466              :                                                         loxhi, 0),
    2467         1126 :                                          hprec - 1, NULL_RTX, 0);
    2468              : 
    2469         3099 :           do_compare_rtx_and_jump (signbitloxhi, hipartloxhi, NE, true, hmode,
    2470              :                                    NULL_RTX, NULL, do_overflow,
    2471              :                                    profile_probability::very_unlikely ());
    2472              : 
    2473              :           /* res = (loxhi << (bitsize / 2)) | (hmode) lo0xlo1;  */
    2474         3099 :           rtx loxhishifted = expand_shift (LSHIFT_EXPR, mode, loxhi, hprec,
    2475              :                                            NULL_RTX, 1);
    2476         3099 :           tem = convert_modes (mode, hmode,
    2477              :                                convert_modes (hmode, mode, lo0xlo1, 1), 1);
    2478              : 
    2479         3099 :           tem = expand_simple_binop (mode, IOR, loxhishifted, tem, res,
    2480              :                                      1, OPTAB_WIDEN);
    2481         3099 :           if (tem != res)
    2482            0 :             emit_move_insn (res, tem);
    2483         3099 :           emit_jump (done_label);
    2484              : 
    2485         3099 :           emit_label (both_ops_large);
    2486              : 
    2487              :           /* If both operands are large (not sign (!uns) or zero (uns)
    2488              :              extended from hmode), then perform the full multiplication
    2489              :              which will be the result of the operation.
    2490              :              The only cases which don't overflow are for signed multiplication
    2491              :              some cases where both hipart0 and highpart1 are 0 or -1.
    2492              :              For unsigned multiplication when high parts are both non-zero
    2493              :              this overflows always.  */
    2494         3099 :           ops.code = MULT_EXPR;
    2495         3099 :           ops.op0 = make_tree (type, op0);
    2496         3099 :           ops.op1 = make_tree (type, op1);
    2497         3099 :           tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2498         3099 :           emit_move_insn (res, tem);
    2499              : 
    2500         3099 :           if (!uns)
    2501              :             {
    2502         1126 :               if (!op0_medium_p)
    2503              :                 {
    2504         1126 :                   tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
    2505              :                                              NULL_RTX, 1, OPTAB_WIDEN);
    2506         1126 :                   do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
    2507              :                                            NULL_RTX, NULL, do_error,
    2508              :                                            profile_probability::very_unlikely ());
    2509              :                 }
    2510              : 
    2511         1126 :               if (!op1_medium_p)
    2512              :                 {
    2513         1126 :                   tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
    2514              :                                              NULL_RTX, 1, OPTAB_WIDEN);
    2515         1126 :                   do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
    2516              :                                            NULL_RTX, NULL, do_error,
    2517              :                                            profile_probability::very_unlikely ());
    2518              :                 }
    2519              : 
    2520              :               /* At this point hipart{0,1} are both in [-1, 0].  If they are
    2521              :                  the same, overflow happened if res is non-positive, if they
    2522              :                  are different, overflow happened if res is positive.  */
    2523         1126 :               if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
    2524           12 :                 emit_jump (hipart_different);
    2525         1114 :               else if (op0_sign == 1 || op1_sign == 1)
    2526         1058 :                 do_compare_rtx_and_jump (hipart0, hipart1, NE, true, hmode,
    2527              :                                          NULL_RTX, NULL, hipart_different,
    2528              :                                          profile_probability::even ());
    2529              : 
    2530         1126 :               do_compare_rtx_and_jump (res, const0_rtx, LE, false, mode,
    2531              :                                        NULL_RTX, NULL, do_error,
    2532              :                                        profile_probability::very_unlikely ());
    2533         1126 :               emit_jump (done_label);
    2534              : 
    2535         1126 :               emit_label (hipart_different);
    2536              : 
    2537         1126 :               do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode,
    2538              :                                        NULL_RTX, NULL, do_error,
    2539              :                                        profile_probability::very_unlikely ());
    2540         1126 :               emit_jump (done_label);
    2541              :             }
    2542              : 
    2543         3099 :           emit_label (do_overflow);
    2544              : 
    2545              :           /* Overflow, do full multiplication and fallthru into do_error.  */
    2546         3099 :           ops.op0 = make_tree (type, op0);
    2547         3099 :           ops.op1 = make_tree (type, op1);
    2548         3099 :           tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2549         3099 :           emit_move_insn (res, tem);
    2550              :         }
    2551            0 :       else if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
    2552            0 :                && targetm.scalar_mode_supported_p (wmode))
    2553              :         /* Even emitting a libcall is better than not detecting overflow
    2554              :            at all.  */
    2555            0 :         goto twoxwider;
    2556              :       else
    2557              :         {
    2558            0 :           gcc_assert (!is_ubsan);
    2559            0 :           ops.code = MULT_EXPR;
    2560            0 :           ops.type = type;
    2561            0 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2562            0 :           emit_jump (done_label);
    2563              :         }
    2564              :     }
    2565              : 
    2566        13832 :  do_error_label:
    2567        18898 :   emit_label (do_error);
    2568        18898 :   if (is_ubsan)
    2569              :     {
    2570              :       /* Expand the ubsan builtin call.  */
    2571         1510 :       push_temp_slots ();
    2572         1510 :       fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (orig_arg0),
    2573              :                                          orig_arg0, orig_arg1, datap);
    2574         1510 :       expand_normal (fn);
    2575         1510 :       pop_temp_slots ();
    2576         1510 :       do_pending_stack_adjust ();
    2577              :     }
    2578        17388 :   else if (lhs)
    2579        17388 :     expand_arith_set_overflow (lhs, target);
    2580              : 
    2581              :   /* We're done.  */
    2582        18898 :   emit_label (done_label);
    2583              : 
    2584              :   /* u1 * u2 -> sr  */
    2585        18898 :   if (uns0_p && uns1_p && !unsr_p)
    2586              :     {
    2587          957 :       rtx_code_label *all_done_label = gen_label_rtx ();
    2588          957 :       do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
    2589              :                                NULL, all_done_label, profile_probability::very_likely ());
    2590          957 :       expand_arith_set_overflow (lhs, target);
    2591          957 :       emit_label (all_done_label);
    2592              :     }
    2593              : 
    2594              :   /* s1 * u2 -> sr  */
    2595        18898 :   if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
    2596              :     {
    2597         1273 :       rtx_code_label *all_done_label = gen_label_rtx ();
    2598         1273 :       rtx_code_label *set_noovf = gen_label_rtx ();
    2599         1273 :       do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
    2600              :                                NULL, all_done_label, profile_probability::very_likely ());
    2601         1273 :       expand_arith_set_overflow (lhs, target);
    2602         1273 :       do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
    2603              :                                NULL, set_noovf, profile_probability::very_likely ());
    2604         1273 :       do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
    2605              :                                NULL, all_done_label, profile_probability::very_unlikely ());
    2606         1273 :       do_compare_rtx_and_jump (op1, res, NE, true, mode, NULL_RTX, NULL,
    2607              :                                all_done_label, profile_probability::very_unlikely ());
    2608         1273 :       emit_label (set_noovf);
    2609         1273 :       write_complex_part (target, const0_rtx, true, false);
    2610         1273 :       emit_label (all_done_label);
    2611              :     }
    2612              : 
    2613        18898 :   if (lhs)
    2614              :     {
    2615        18754 :       if (is_ubsan)
    2616         1366 :         expand_ubsan_result_store (lhs, target, mode, res, do_error);
    2617              :       else
    2618        17388 :         expand_arith_overflow_result_store (lhs, target, mode, res);
    2619              :     }
    2620        18898 :   flag_trapv = save_flag_trapv;
    2621        18898 : }
    2622              : 
    2623              : /* Expand UBSAN_CHECK_* internal function if it has vector operands.  */
    2624              : 
    2625              : static void
    2626          567 : expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs,
    2627              :                               tree arg0, tree arg1)
    2628              : {
    2629          567 :   poly_uint64 cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
    2630          567 :   rtx_code_label *loop_lab = NULL;
    2631          567 :   rtx cntvar = NULL_RTX;
    2632          567 :   tree cntv = NULL_TREE;
    2633          567 :   tree eltype = TREE_TYPE (TREE_TYPE (arg0));
    2634          567 :   tree sz = TYPE_SIZE (eltype);
    2635          567 :   tree data = NULL_TREE;
    2636          567 :   tree resv = NULL_TREE;
    2637          567 :   rtx lhsr = NULL_RTX;
    2638          567 :   rtx resvr = NULL_RTX;
    2639          567 :   unsigned HOST_WIDE_INT const_cnt = 0;
    2640          567 :   bool use_loop_p = (!cnt.is_constant (&const_cnt) || const_cnt > 4);
    2641          567 :   int save_flag_trapv = flag_trapv;
    2642              : 
    2643              :   /* We don't want any __mulv?i3 etc. calls from the expansion of
    2644              :      these internal functions, so disable -ftrapv temporarily.  */
    2645          567 :   flag_trapv = 0;
    2646          567 :   if (lhs)
    2647              :     {
    2648          567 :       optab op;
    2649          567 :       lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    2650          141 :       if (!VECTOR_MODE_P (GET_MODE (lhsr))
    2651          426 :           || (op = optab_for_tree_code (code, TREE_TYPE (arg0),
    2652              :                                         optab_default)) == unknown_optab
    2653          993 :           || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0)))
    2654              :               == CODE_FOR_nothing))
    2655              :         {
    2656          141 :           if (MEM_P (lhsr))
    2657          141 :             resv = make_tree (TREE_TYPE (lhs), lhsr);
    2658              :           else
    2659              :             {
    2660            0 :               resvr = assign_temp (TREE_TYPE (lhs), 1, 1);
    2661            0 :               resv = make_tree (TREE_TYPE (lhs), resvr);
    2662              :             }
    2663              :         }
    2664              :     }
    2665          567 :   if (use_loop_p)
    2666              :     {
    2667          417 :       do_pending_stack_adjust ();
    2668          417 :       loop_lab = gen_label_rtx ();
    2669          417 :       cntvar = gen_reg_rtx (TYPE_MODE (sizetype));
    2670          417 :       cntv = make_tree (sizetype, cntvar);
    2671          417 :       emit_move_insn (cntvar, const0_rtx);
    2672          417 :       emit_label (loop_lab);
    2673              :     }
    2674          567 :   if (TREE_CODE (arg0) != VECTOR_CST)
    2675              :     {
    2676          461 :       rtx arg0r = expand_normal (arg0);
    2677          461 :       arg0 = make_tree (TREE_TYPE (arg0), arg0r);
    2678              :     }
    2679          567 :   if (TREE_CODE (arg1) != VECTOR_CST)
    2680              :     {
    2681          555 :       rtx arg1r = expand_normal (arg1);
    2682          555 :       arg1 = make_tree (TREE_TYPE (arg1), arg1r);
    2683              :     }
    2684         2334 :   for (unsigned int i = 0; i < (use_loop_p ? 1 : const_cnt); i++)
    2685              :     {
    2686         1017 :       tree op0, op1, res = NULL_TREE;
    2687         1017 :       if (use_loop_p)
    2688              :         {
    2689          417 :           tree atype = build_array_type_nelts (eltype, cnt);
    2690          417 :           op0 = uniform_vector_p (arg0);
    2691          417 :           if (op0 == NULL_TREE)
    2692              :             {
    2693          351 :               op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0);
    2694          351 :               op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv,
    2695              :                                 NULL_TREE, NULL_TREE);
    2696              :             }
    2697          417 :           op1 = uniform_vector_p (arg1);
    2698          417 :           if (op1 == NULL_TREE)
    2699              :             {
    2700          411 :               op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1);
    2701          411 :               op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv,
    2702              :                                 NULL_TREE, NULL_TREE);
    2703              :             }
    2704          417 :           if (resv)
    2705              :             {
    2706          141 :               res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv);
    2707          141 :               res = build4_loc (loc, ARRAY_REF, eltype, res, cntv,
    2708              :                                 NULL_TREE, NULL_TREE);
    2709              :             }
    2710              :         }
    2711              :       else
    2712              :         {
    2713          600 :           tree bitpos = bitsize_int (tree_to_uhwi (sz) * i);
    2714          600 :           op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos);
    2715          600 :           op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos);
    2716          600 :           if (resv)
    2717            0 :             res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz,
    2718              :                                    bitpos);
    2719              :         }
    2720         1017 :       switch (code)
    2721              :         {
    2722          317 :         case PLUS_EXPR:
    2723          317 :           expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1,
    2724              :                                   false, false, false, true, &data);
    2725          317 :           break;
    2726          534 :         case MINUS_EXPR:
    2727          534 :           if (use_loop_p ? integer_zerop (arg0) : integer_zerop (op0))
    2728          226 :             expand_neg_overflow (loc, res, op1, true, &data);
    2729              :           else
    2730          308 :             expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1,
    2731              :                                     false, false, false, true, &data);
    2732              :           break;
    2733          166 :         case MULT_EXPR:
    2734          166 :           expand_mul_overflow (loc, res, op0, op1, false, false, false,
    2735              :                                true, &data);
    2736          166 :           break;
    2737            0 :         default:
    2738            0 :           gcc_unreachable ();
    2739              :         }
    2740              :     }
    2741          567 :   if (use_loop_p)
    2742              :     {
    2743          417 :       struct separate_ops ops;
    2744          417 :       ops.code = PLUS_EXPR;
    2745          417 :       ops.type = TREE_TYPE (cntv);
    2746          417 :       ops.op0 = cntv;
    2747          417 :       ops.op1 = build_int_cst (TREE_TYPE (cntv), 1);
    2748          417 :       ops.op2 = NULL_TREE;
    2749          417 :       ops.location = loc;
    2750          417 :       rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype),
    2751              :                                     EXPAND_NORMAL);
    2752          417 :       if (ret != cntvar)
    2753            0 :         emit_move_insn (cntvar, ret);
    2754          417 :       rtx cntrtx = gen_int_mode (cnt, TYPE_MODE (sizetype));
    2755          834 :       do_compare_rtx_and_jump (cntvar, cntrtx, NE, false,
    2756          417 :                                TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab,
    2757              :                                profile_probability::very_likely ());
    2758              :     }
    2759          567 :   if (lhs && resv == NULL_TREE)
    2760              :     {
    2761          426 :       struct separate_ops ops;
    2762          426 :       ops.code = code;
    2763          426 :       ops.type = TREE_TYPE (arg0);
    2764          426 :       ops.op0 = arg0;
    2765          426 :       ops.op1 = arg1;
    2766          426 :       ops.op2 = NULL_TREE;
    2767          426 :       ops.location = loc;
    2768          426 :       rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)),
    2769              :                                     EXPAND_NORMAL);
    2770          426 :       if (ret != lhsr)
    2771            5 :         emit_move_insn (lhsr, ret);
    2772              :     }
    2773          141 :   else if (resvr)
    2774            0 :     emit_move_insn (lhsr, resvr);
    2775          567 :   flag_trapv = save_flag_trapv;
    2776          567 : }
    2777              : 
    2778              : /* Expand UBSAN_CHECK_ADD call STMT.  */
    2779              : 
    2780              : static void
    2781         1792 : expand_UBSAN_CHECK_ADD (internal_fn, gcall *stmt)
    2782              : {
    2783         1792 :   location_t loc = gimple_location (stmt);
    2784         1792 :   tree lhs = gimple_call_lhs (stmt);
    2785         1792 :   tree arg0 = gimple_call_arg (stmt, 0);
    2786         1792 :   tree arg1 = gimple_call_arg (stmt, 1);
    2787         1792 :   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
    2788          185 :     expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1);
    2789              :   else
    2790         1607 :     expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
    2791              :                             false, false, false, true, NULL);
    2792         1792 : }
    2793              : 
    2794              : /* Expand UBSAN_CHECK_SUB call STMT.  */
    2795              : 
    2796              : static void
    2797         1865 : expand_UBSAN_CHECK_SUB (internal_fn, gcall *stmt)
    2798              : {
    2799         1865 :   location_t loc = gimple_location (stmt);
    2800         1865 :   tree lhs = gimple_call_lhs (stmt);
    2801         1865 :   tree arg0 = gimple_call_arg (stmt, 0);
    2802         1865 :   tree arg1 = gimple_call_arg (stmt, 1);
    2803         1865 :   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
    2804          282 :     expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1);
    2805         1583 :   else if (integer_zerop (arg0))
    2806          424 :     expand_neg_overflow (loc, lhs, arg1, true, NULL);
    2807              :   else
    2808         1159 :     expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
    2809              :                             false, false, false, true, NULL);
    2810         1865 : }
    2811              : 
    2812              : /* Expand UBSAN_CHECK_MUL call STMT.  */
    2813              : 
    2814              : static void
    2815         1444 : expand_UBSAN_CHECK_MUL (internal_fn, gcall *stmt)
    2816              : {
    2817         1444 :   location_t loc = gimple_location (stmt);
    2818         1444 :   tree lhs = gimple_call_lhs (stmt);
    2819         1444 :   tree arg0 = gimple_call_arg (stmt, 0);
    2820         1444 :   tree arg1 = gimple_call_arg (stmt, 1);
    2821         1444 :   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
    2822          100 :     expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1);
    2823              :   else
    2824         1344 :     expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true,
    2825              :                          NULL);
    2826         1444 : }
    2827              : 
    2828              : /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion.  */
    2829              : 
    2830              : static void
    2831        71836 : expand_arith_overflow (enum tree_code code, gimple *stmt)
    2832              : {
    2833        71836 :   tree lhs = gimple_call_lhs (stmt);
    2834        71836 :   if (lhs == NULL_TREE)
    2835              :     return;
    2836        71836 :   tree arg0 = gimple_call_arg (stmt, 0);
    2837        71836 :   tree arg1 = gimple_call_arg (stmt, 1);
    2838        71836 :   tree type = TREE_TYPE (TREE_TYPE (lhs));
    2839        71836 :   int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
    2840        71836 :   int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
    2841        71836 :   int unsr_p = TYPE_UNSIGNED (type);
    2842        71836 :   int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
    2843        71836 :   int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
    2844        71836 :   int precres = TYPE_PRECISION (type);
    2845        71836 :   location_t loc = gimple_location (stmt);
    2846        71836 :   if (!uns0_p && get_range_pos_neg (arg0, stmt) == 1)
    2847              :     uns0_p = true;
    2848        71836 :   if (!uns1_p && get_range_pos_neg (arg1, stmt) == 1)
    2849              :     uns1_p = true;
    2850       106065 :   int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
    2851        71836 :   prec0 = MIN (prec0, pr);
    2852        96974 :   pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
    2853        71836 :   prec1 = MIN (prec1, pr);
    2854        71836 :   int save_flag_trapv = flag_trapv;
    2855              : 
    2856              :   /* We don't want any __mulv?i3 etc. calls from the expansion of
    2857              :      these internal functions, so disable -ftrapv temporarily.  */
    2858        71836 :   flag_trapv = 0;
    2859              :   /* If uns0_p && uns1_p, precop is minimum needed precision
    2860              :      of unsigned type to hold the exact result, otherwise
    2861              :      precop is minimum needed precision of signed type to
    2862              :      hold the exact result.  */
    2863        71836 :   int precop;
    2864        71836 :   if (code == MULT_EXPR)
    2865        23396 :     precop = prec0 + prec1 + (uns0_p != uns1_p);
    2866              :   else
    2867              :     {
    2868        48440 :       if (uns0_p == uns1_p)
    2869        31324 :         precop = MAX (prec0, prec1) + 1;
    2870        17116 :       else if (uns0_p)
    2871         5815 :         precop = MAX (prec0 + 1, prec1) + 1;
    2872              :       else
    2873        11301 :         precop = MAX (prec0, prec1 + 1) + 1;
    2874              :     }
    2875        71836 :   int orig_precres = precres;
    2876              : 
    2877        91256 :   do
    2878              :     {
    2879        91256 :       if ((uns0_p && uns1_p)
    2880        91256 :           ? ((precop + !unsr_p) <= precres
    2881              :              /* u1 - u2 -> ur can overflow, no matter what precision
    2882              :                 the result has.  */
    2883        33624 :              && (code != MINUS_EXPR || !unsr_p))
    2884        57632 :           : (!unsr_p && precop <= precres))
    2885              :         {
    2886              :           /* The infinity precision result will always fit into result.  */
    2887        18526 :           rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    2888        18526 :           write_complex_part (target, const0_rtx, true, false);
    2889        18526 :           scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
    2890        18526 :           struct separate_ops ops;
    2891        18526 :           ops.code = code;
    2892        18526 :           ops.type = type;
    2893        18526 :           ops.op0 = fold_convert_loc (loc, type, arg0);
    2894        18526 :           ops.op1 = fold_convert_loc (loc, type, arg1);
    2895        18526 :           ops.op2 = NULL_TREE;
    2896        18526 :           ops.location = loc;
    2897        18526 :           rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2898        18526 :           expand_arith_overflow_result_store (lhs, target, mode, tem);
    2899        18526 :           flag_trapv = save_flag_trapv;
    2900        18526 :           return;
    2901              :         }
    2902              : 
    2903              :       /* For operations with low precision, if target doesn't have them, start
    2904              :          with precres widening right away, otherwise do it only if the most
    2905              :          simple cases can't be used.  */
    2906        72730 :       const int min_precision = targetm.min_arithmetic_precision ();
    2907        72730 :       if (orig_precres == precres && precres < min_precision)
    2908              :         ;
    2909        71463 :       else if ((uns0_p && uns1_p && unsr_p && prec0 <= precres
    2910        20782 :                 && prec1 <= precres)
    2911        50684 :           || ((!uns0_p || !uns1_p) && !unsr_p
    2912        20655 :               && prec0 + uns0_p <= precres
    2913        17465 :               && prec1 + uns1_p <= precres))
    2914              :         {
    2915        34086 :           arg0 = fold_convert_loc (loc, type, arg0);
    2916        34086 :           arg1 = fold_convert_loc (loc, type, arg1);
    2917        34086 :           switch (code)
    2918              :             {
    2919         9845 :             case MINUS_EXPR:
    2920         9845 :               if (integer_zerop (arg0) && !unsr_p)
    2921              :                 {
    2922          402 :                   expand_neg_overflow (loc, lhs, arg1, false, NULL);
    2923          402 :                   flag_trapv = save_flag_trapv;
    2924          402 :                   return;
    2925              :                 }
    2926              :               /* FALLTHRU */
    2927        24036 :             case PLUS_EXPR:
    2928        24036 :               expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
    2929              :                                       unsr_p, unsr_p, false, NULL);
    2930        24036 :               flag_trapv = save_flag_trapv;
    2931        24036 :               return;
    2932         9648 :             case MULT_EXPR:
    2933         9648 :               expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
    2934              :                                    unsr_p, unsr_p, false, NULL);
    2935         9648 :               flag_trapv = save_flag_trapv;
    2936         9648 :               return;
    2937            0 :             default:
    2938            0 :               gcc_unreachable ();
    2939              :             }
    2940              :         }
    2941              : 
    2942              :       /* For sub-word operations, retry with a wider type first.  */
    2943        38645 :       if (orig_precres == precres && precop <= BITS_PER_WORD)
    2944              :         {
    2945        19508 :           int p = MAX (min_precision, precop);
    2946        19508 :           scalar_int_mode m = smallest_int_mode_for_size (p).require ();
    2947        19508 :           tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
    2948              :                                                         uns0_p && uns1_p
    2949        19508 :                                                         && unsr_p);
    2950        19508 :           p = TYPE_PRECISION (optype);
    2951        19508 :           if (p > precres)
    2952              :             {
    2953        18805 :               precres = p;
    2954        18805 :               unsr_p = TYPE_UNSIGNED (optype);
    2955        18805 :               type = optype;
    2956        18805 :               continue;
    2957              :             }
    2958              :         }
    2959              : 
    2960        19839 :       if (prec0 <= precres && prec1 <= precres)
    2961              :         {
    2962        19224 :           tree types[2];
    2963        19224 :           if (unsr_p)
    2964              :             {
    2965        11083 :               types[0] = build_nonstandard_integer_type (precres, 0);
    2966        11083 :               types[1] = type;
    2967              :             }
    2968              :           else
    2969              :             {
    2970         8141 :               types[0] = type;
    2971         8141 :               types[1] = build_nonstandard_integer_type (precres, 1);
    2972              :             }
    2973        19224 :           arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
    2974        19224 :           arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
    2975        19224 :           if (code != MULT_EXPR)
    2976        11484 :             expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
    2977              :                                     uns0_p, uns1_p, false, NULL);
    2978              :           else
    2979         7740 :             expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
    2980              :                                  uns0_p, uns1_p, false, NULL);
    2981        19224 :           flag_trapv = save_flag_trapv;
    2982        19224 :           return;
    2983              :         }
    2984              : 
    2985              :       /* Retry with a wider type.  */
    2986          615 :       if (orig_precres == precres)
    2987              :         {
    2988          615 :           int p = MAX (prec0, prec1);
    2989          615 :           scalar_int_mode m = smallest_int_mode_for_size (p).require ();
    2990          615 :           tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
    2991              :                                                         uns0_p && uns1_p
    2992          615 :                                                         && unsr_p);
    2993          615 :           p = TYPE_PRECISION (optype);
    2994          615 :           if (p > precres)
    2995              :             {
    2996          615 :               precres = p;
    2997          615 :               unsr_p = TYPE_UNSIGNED (optype);
    2998          615 :               type = optype;
    2999          615 :               continue;
    3000              :             }
    3001              :         }
    3002              : 
    3003            0 :       gcc_unreachable ();
    3004              :     }
    3005              :   while (1);
    3006              : }
    3007              : 
    3008              : /* Expand ADD_OVERFLOW STMT.  */
    3009              : 
    3010              : static void
    3011        24964 : expand_ADD_OVERFLOW (internal_fn, gcall *stmt)
    3012              : {
    3013        24964 :   expand_arith_overflow (PLUS_EXPR, stmt);
    3014        24964 : }
    3015              : 
    3016              : /* Expand SUB_OVERFLOW STMT.  */
    3017              : 
    3018              : static void
    3019        23476 : expand_SUB_OVERFLOW (internal_fn, gcall *stmt)
    3020              : {
    3021        23476 :   expand_arith_overflow (MINUS_EXPR, stmt);
    3022        23476 : }
    3023              : 
    3024              : /* Expand MUL_OVERFLOW STMT.  */
    3025              : 
    3026              : static void
    3027        23396 : expand_MUL_OVERFLOW (internal_fn, gcall *stmt)
    3028              : {
    3029        23396 :   expand_arith_overflow (MULT_EXPR, stmt);
    3030        23396 : }
    3031              : 
    3032              : /* Expand UADDC STMT.  */
    3033              : 
    3034              : static void
    3035        15899 : expand_UADDC (internal_fn ifn, gcall *stmt)
    3036              : {
    3037        15899 :   tree lhs = gimple_call_lhs (stmt);
    3038        15899 :   tree arg1 = gimple_call_arg (stmt, 0);
    3039        15899 :   tree arg2 = gimple_call_arg (stmt, 1);
    3040        15899 :   tree arg3 = gimple_call_arg (stmt, 2);
    3041        15899 :   tree type = TREE_TYPE (arg1);
    3042        15899 :   machine_mode mode = TYPE_MODE (type);
    3043        22394 :   insn_code icode = optab_handler (ifn == IFN_UADDC
    3044              :                                    ? uaddc5_optab : usubc5_optab, mode);
    3045        15899 :   rtx op1 = expand_normal (arg1);
    3046        15899 :   rtx op2 = expand_normal (arg2);
    3047        15899 :   rtx op3 = expand_normal (arg3);
    3048        15899 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3049        15899 :   rtx re = gen_reg_rtx (mode);
    3050        15899 :   rtx im = gen_reg_rtx (mode);
    3051        15899 :   class expand_operand ops[5];
    3052        15899 :   create_output_operand (&ops[0], re, mode);
    3053        15899 :   create_output_operand (&ops[1], im, mode);
    3054        15899 :   create_input_operand (&ops[2], op1, mode);
    3055        15899 :   create_input_operand (&ops[3], op2, mode);
    3056        15899 :   create_input_operand (&ops[4], op3, mode);
    3057        15899 :   expand_insn (icode, 5, ops);
    3058        15899 :   write_complex_part (target, re, false, false);
    3059        15899 :   write_complex_part (target, im, true, false);
    3060        15899 : }
    3061              : 
    3062              : /* Expand USUBC STMT.  */
    3063              : 
    3064              : static void
    3065         6495 : expand_USUBC (internal_fn ifn, gcall *stmt)
    3066              : {
    3067         6495 :   expand_UADDC (ifn, stmt);
    3068         6495 : }
    3069              : 
    3070              : /* This should get folded in tree-vectorizer.cc.  */
    3071              : 
    3072              : static void
    3073            0 : expand_LOOP_VECTORIZED (internal_fn, gcall *)
    3074              : {
    3075            0 :   gcc_unreachable ();
    3076              : }
    3077              : 
    3078              : /* This should get folded in tree-vectorizer.cc.  */
    3079              : 
    3080              : static void
    3081            0 : expand_LOOP_DIST_ALIAS (internal_fn, gcall *)
    3082              : {
    3083            0 :   gcc_unreachable ();
    3084              : }
    3085              : 
    3086              : /* Return a memory reference of type TYPE for argument INDEX of STMT.
    3087              :    Use argument INDEX + 1 to derive the second (TBAA) operand.  */
    3088              : 
    3089              : static tree
    3090         1401 : expand_call_mem_ref (tree type, gcall *stmt, int index)
    3091              : {
    3092         1401 :   tree addr = gimple_call_arg (stmt, index);
    3093         1401 :   tree alias_ptr_type = TREE_TYPE (gimple_call_arg (stmt, index + 1));
    3094         1401 :   unsigned int align = tree_to_shwi (gimple_call_arg (stmt, index + 1));
    3095         1401 :   if (TYPE_ALIGN (type) != align)
    3096         1139 :     type = build_aligned_type (type, align);
    3097              : 
    3098         1401 :   tree tmp = addr;
    3099         1401 :   if (TREE_CODE (tmp) == SSA_NAME)
    3100              :     {
    3101         1263 :       gimple *def = get_gimple_for_ssa_name (tmp);
    3102         1263 :       if (def && gimple_assign_single_p (def))
    3103          562 :         tmp = gimple_assign_rhs1 (def);
    3104              :     }
    3105              : 
    3106         1401 :   if (TREE_CODE (tmp) == ADDR_EXPR)
    3107              :     {
    3108          700 :       tree mem = TREE_OPERAND (tmp, 0);
    3109          700 :       if (TREE_CODE (mem) == TARGET_MEM_REF
    3110          700 :           && types_compatible_p (TREE_TYPE (mem), type))
    3111              :         {
    3112          562 :           tree offset = TMR_OFFSET (mem);
    3113          562 :           if (type != TREE_TYPE (mem)
    3114          132 :               || alias_ptr_type != TREE_TYPE (offset)
    3115          694 :               || !integer_zerop (offset))
    3116              :             {
    3117          457 :               mem = copy_node (mem);
    3118          914 :               TMR_OFFSET (mem) = wide_int_to_tree (alias_ptr_type,
    3119          457 :                                                    wi::to_poly_wide (offset));
    3120          457 :               TREE_TYPE (mem) = type;
    3121              :             }
    3122              :           return mem;
    3123              :         }
    3124              :     }
    3125              : 
    3126          839 :   return fold_build2 (MEM_REF, type, addr, build_int_cst (alias_ptr_type, 0));
    3127              : }
    3128              : 
    3129              : /* Expand MASK_LOAD{,_LANES}, MASK_LEN_LOAD or LEN_LOAD call STMT using optab
    3130              :  * OPTAB.  */
    3131              : 
    3132              : static void
    3133          675 : expand_partial_load_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
    3134              : {
    3135          675 :   int i = 0;
    3136          675 :   class expand_operand ops[6];
    3137          675 :   tree type, lhs, rhs, maskt;
    3138          675 :   rtx mem, target;
    3139          675 :   insn_code icode;
    3140              : 
    3141          675 :   maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
    3142          675 :   lhs = gimple_call_lhs (stmt);
    3143          675 :   if (lhs == NULL_TREE)
    3144            0 :     return;
    3145          675 :   type = TREE_TYPE (lhs);
    3146          675 :   rhs = expand_call_mem_ref (type, stmt, 0);
    3147              : 
    3148          675 :   if (optab == vec_mask_load_lanes_optab
    3149          675 :       || optab == vec_mask_len_load_lanes_optab)
    3150            0 :     icode = get_multi_vector_move (type, optab);
    3151          675 :   else if (optab == len_load_optab)
    3152            0 :     icode = direct_optab_handler (optab, TYPE_MODE (type));
    3153              :   else
    3154          675 :     icode = convert_optab_handler (optab, TYPE_MODE (type),
    3155          675 :                                    TYPE_MODE (TREE_TYPE (maskt)));
    3156              : 
    3157          675 :   mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_MEMORY);
    3158          675 :   gcc_assert (MEM_P (mem));
    3159          675 :   MEM_NOTRAP_P (mem) = !tree_could_trap_p (rhs);
    3160              :   /* The built MEM_REF does not accurately reflect that the load
    3161              :      is only partial.  Clear it.  */
    3162          675 :   set_mem_expr (mem, NULL_TREE);
    3163          675 :   clear_mem_offset (mem);
    3164          675 :   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3165          675 :   create_call_lhs_operand (&ops[i++], target, TYPE_MODE (type));
    3166          675 :   create_fixed_operand (&ops[i++], mem);
    3167          675 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3168          675 :   expand_insn (icode, i, ops);
    3169              : 
    3170          675 :   assign_call_lhs (lhs, target, &ops[0]);
    3171              : }
    3172              : 
    3173              : #define expand_mask_load_optab_fn expand_partial_load_optab_fn
    3174              : #define expand_mask_load_lanes_optab_fn expand_mask_load_optab_fn
    3175              : #define expand_len_load_optab_fn expand_partial_load_optab_fn
    3176              : #define expand_mask_len_load_optab_fn expand_partial_load_optab_fn
    3177              : 
    3178              : /* Expand MASK_STORE{,_LANES}, MASK_LEN_STORE or LEN_STORE call STMT using optab
    3179              :  * OPTAB.  */
    3180              : 
    3181              : static void
    3182          726 : expand_partial_store_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
    3183              : {
    3184          726 :   int i = 0;
    3185          726 :   class expand_operand ops[5];
    3186          726 :   tree type, lhs, rhs, maskt;
    3187          726 :   rtx mem, reg;
    3188          726 :   insn_code icode;
    3189              : 
    3190          726 :   maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
    3191          726 :   rhs = gimple_call_arg (stmt, internal_fn_stored_value_index (ifn));
    3192          726 :   type = TREE_TYPE (rhs);
    3193          726 :   lhs = expand_call_mem_ref (type, stmt, 0);
    3194              : 
    3195          726 :   if (optab == vec_mask_store_lanes_optab
    3196          726 :       || optab == vec_mask_len_store_lanes_optab)
    3197            0 :     icode = get_multi_vector_move (type, optab);
    3198          726 :   else if (optab == len_store_optab)
    3199            0 :     icode = direct_optab_handler (optab, TYPE_MODE (type));
    3200              :   else
    3201          726 :     icode = convert_optab_handler (optab, TYPE_MODE (type),
    3202          726 :                                    TYPE_MODE (TREE_TYPE (maskt)));
    3203              : 
    3204          726 :   mem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3205          726 :   gcc_assert (MEM_P (mem));
    3206              :   /* The built MEM_REF does not accurately reflect that the store
    3207              :      is only partial.  Clear it.  */
    3208          726 :   set_mem_expr (mem, NULL_TREE);
    3209          726 :   clear_mem_offset (mem);
    3210          726 :   reg = expand_normal (rhs);
    3211          726 :   create_fixed_operand (&ops[i++], mem);
    3212          726 :   create_input_operand (&ops[i++], reg, TYPE_MODE (type));
    3213          726 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3214          726 :   expand_insn (icode, i, ops);
    3215          726 : }
    3216              : 
    3217              : #define expand_mask_store_optab_fn expand_partial_store_optab_fn
    3218              : #define expand_mask_store_lanes_optab_fn expand_mask_store_optab_fn
    3219              : #define expand_len_store_optab_fn expand_partial_store_optab_fn
    3220              : #define expand_mask_len_store_optab_fn expand_partial_store_optab_fn
    3221              : 
    3222              : /* Expand VCOND_MASK optab internal function.
    3223              :    The expansion of STMT happens based on OPTAB table associated.  */
    3224              : 
    3225              : static void
    3226         9267 : expand_vec_cond_mask_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
    3227              : {
    3228         9267 :   class expand_operand ops[4];
    3229              : 
    3230         9267 :   tree lhs = gimple_call_lhs (stmt);
    3231         9267 :   tree op0 = gimple_call_arg (stmt, 0);
    3232         9267 :   tree op1 = gimple_call_arg (stmt, 1);
    3233         9267 :   tree op2 = gimple_call_arg (stmt, 2);
    3234         9267 :   tree vec_cond_type = TREE_TYPE (lhs);
    3235              : 
    3236         9267 :   machine_mode mode = TYPE_MODE (vec_cond_type);
    3237         9267 :   machine_mode mask_mode = TYPE_MODE (TREE_TYPE (op0));
    3238         9267 :   enum insn_code icode = convert_optab_handler (optab, mode, mask_mode);
    3239         9267 :   rtx mask, rtx_op1, rtx_op2;
    3240              : 
    3241         9267 :   gcc_assert (icode != CODE_FOR_nothing);
    3242              : 
    3243              :   /* Find the comparison generating the mask OP0.  */
    3244         9267 :   tree cmp_op0 = NULL_TREE;
    3245         9267 :   tree cmp_op1 = NULL_TREE;
    3246         9267 :   enum tree_code cmp_code = TREE_CODE (op0);
    3247         9267 :   if (TREE_CODE_CLASS (cmp_code) == tcc_comparison)
    3248              :     {
    3249            0 :       cmp_op0 = TREE_OPERAND (op0, 0);
    3250            0 :       cmp_op1 = TREE_OPERAND (op0, 1);
    3251              :     }
    3252         9267 :   else if (cmp_code == SSA_NAME)
    3253              :     {
    3254         7931 :       gimple *def_stmt = get_gimple_for_ssa_name (op0);
    3255         7931 :       if (def_stmt && is_gimple_assign (def_stmt))
    3256              :         {
    3257         6314 :           cmp_code = gimple_assign_rhs_code (def_stmt);
    3258         6314 :           if (TREE_CODE_CLASS (cmp_code) == tcc_comparison)
    3259              :             {
    3260         4604 :               cmp_op0 = gimple_assign_rhs1 (def_stmt);
    3261         4604 :               cmp_op1 = gimple_assign_rhs2 (def_stmt);
    3262              :             }
    3263              :         }
    3264              :     }
    3265              : 
    3266              :   /* Decide whether to invert comparison based on rtx_cost.  */
    3267         4604 :   if (cmp_op0)
    3268              :     {
    3269         4604 :       enum tree_code rev_code;
    3270         4604 :       tree op_type = TREE_TYPE (cmp_op0);
    3271         4604 :       int unsignedp = TYPE_UNSIGNED (op_type);
    3272         4604 :       rev_code = invert_tree_comparison (cmp_code, HONOR_NANS (op_type));
    3273              : 
    3274         4604 :       if (rev_code != ERROR_MARK)
    3275              :         {
    3276         3373 :           tree cmp_type = TREE_TYPE (op0);
    3277         3373 :           machine_mode cmp_mode = TYPE_MODE (cmp_type);
    3278         3373 :           machine_mode op_mode = TYPE_MODE (op_type);
    3279         3373 :           bool speed_p = optimize_insn_for_speed_p ();
    3280         3373 :           rtx reg = gen_raw_REG (op_mode, LAST_VIRTUAL_REGISTER + 1);
    3281         3373 :           enum rtx_code cmp_rtx_code = convert_tree_comp_to_rtx (cmp_code,
    3282              :                                                                  unsignedp);
    3283         3373 :           rtx veccmp = gen_rtx_fmt_ee (cmp_rtx_code, cmp_mode, reg, reg);
    3284         3373 :           int old_cost = rtx_cost (veccmp, cmp_mode, SET, 0, speed_p);
    3285         3373 :           enum rtx_code rev_rtx_code = convert_tree_comp_to_rtx (rev_code,
    3286              :                                                                  unsignedp);
    3287         3373 :           PUT_CODE (veccmp, rev_rtx_code);
    3288         3373 :           int new_cost = rtx_cost (veccmp, cmp_mode, SET, 0, speed_p);
    3289         3373 :           if (new_cost < old_cost)
    3290              :             {
    3291          359 :               op0 = fold_build2_loc (EXPR_LOCATION (op0), rev_code,
    3292              :                                      cmp_type, cmp_op0, cmp_op1);
    3293          359 :               std::swap (op1, op2);
    3294              :             }
    3295              : 
    3296         3373 :           if (dump_file && (dump_flags & TDF_DETAILS))
    3297              :             {
    3298            0 :               fprintf (dump_file,
    3299              :                        ";; %sswapping operands of .VCOND_MASK\n",
    3300              :                        new_cost >= old_cost ? "not " : "");
    3301            0 :               fprintf (dump_file,
    3302              :                        ";; cost of original %s: %d\n",
    3303            0 :                        GET_RTX_NAME (cmp_rtx_code), old_cost);
    3304            0 :               fprintf (dump_file,
    3305              :                        ";; cost of replacement %s: %d\n",
    3306            0 :                        GET_RTX_NAME (rev_rtx_code), new_cost);
    3307              :             }
    3308              :         }
    3309              :     }
    3310              : 
    3311         9267 :   mask = expand_normal (op0);
    3312         9267 :   rtx_op1 = expand_normal (op1);
    3313         9267 :   rtx_op2 = expand_normal (op2);
    3314              : 
    3315         9267 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3316         9267 :   create_call_lhs_operand (&ops[0], target, mode);
    3317         9267 :   create_input_operand (&ops[1], rtx_op1, mode);
    3318         9267 :   create_input_operand (&ops[2], rtx_op2, mode);
    3319         9267 :   create_input_operand (&ops[3], mask, mask_mode);
    3320         9267 :   expand_insn (icode, 4, ops);
    3321         9267 :   assign_call_lhs (lhs, target, &ops[0]);
    3322         9267 : }
    3323              : 
    3324              : /* Expand VEC_SET internal functions.  */
    3325              : 
    3326              : static void
    3327          123 : expand_vec_set_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
    3328              : {
    3329          123 :   tree lhs = gimple_call_lhs (stmt);
    3330          123 :   tree op0 = gimple_call_arg (stmt, 0);
    3331          123 :   tree op1 = gimple_call_arg (stmt, 1);
    3332          123 :   tree op2 = gimple_call_arg (stmt, 2);
    3333          123 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3334          123 :   rtx src = expand_normal (op0);
    3335              : 
    3336          123 :   machine_mode outermode = TYPE_MODE (TREE_TYPE (op0));
    3337          123 :   scalar_mode innermode = GET_MODE_INNER (outermode);
    3338              : 
    3339          123 :   rtx value = expand_normal (op1);
    3340          123 :   rtx pos = expand_normal (op2);
    3341              : 
    3342          123 :   class expand_operand ops[3];
    3343          123 :   enum insn_code icode = optab_handler (optab, outermode);
    3344              : 
    3345          123 :   if (icode != CODE_FOR_nothing)
    3346              :     {
    3347          123 :       rtx temp = gen_reg_rtx (outermode);
    3348          123 :       emit_move_insn (temp, src);
    3349              : 
    3350          123 :       create_fixed_operand (&ops[0], temp);
    3351          123 :       create_input_operand (&ops[1], value, innermode);
    3352          123 :       create_convert_operand_from (&ops[2], pos, TYPE_MODE (TREE_TYPE (op2)),
    3353              :                                    true);
    3354          123 :       if (maybe_expand_insn (icode, 3, ops))
    3355              :         {
    3356          123 :           emit_move_insn (target, temp);
    3357          123 :           return;
    3358              :         }
    3359              :     }
    3360            0 :   gcc_unreachable ();
    3361              : }
    3362              : 
    3363              : static void
    3364         1872 : expand_ABNORMAL_DISPATCHER (internal_fn, gcall *)
    3365              : {
    3366         1872 : }
    3367              : 
    3368              : static void
    3369            0 : expand_BUILTIN_EXPECT (internal_fn, gcall *stmt)
    3370              : {
    3371              :   /* When guessing was done, the hints should be already stripped away.  */
    3372            0 :   gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ());
    3373              : 
    3374            0 :   rtx target;
    3375            0 :   tree lhs = gimple_call_lhs (stmt);
    3376            0 :   if (lhs)
    3377            0 :     target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3378              :   else
    3379            0 :     target = const0_rtx;
    3380            0 :   rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL);
    3381            0 :   if (lhs && val != target)
    3382            0 :     emit_move_insn (target, val);
    3383            0 : }
    3384              : 
    3385              : /* IFN_VA_ARG is supposed to be expanded at pass_stdarg.  So this dummy function
    3386              :    should never be called.  */
    3387              : 
    3388              : static void
    3389            0 : expand_VA_ARG (internal_fn, gcall *)
    3390              : {
    3391            0 :   gcc_unreachable ();
    3392              : }
    3393              : 
    3394              : /* IFN_VEC_CONVERT is supposed to be expanded at pass_lower_vector.  So this
    3395              :    dummy function should never be called.  */
    3396              : 
    3397              : static void
    3398            0 : expand_VEC_CONVERT (internal_fn, gcall *)
    3399              : {
    3400            0 :   gcc_unreachable ();
    3401              : }
    3402              : 
    3403              : /* Expand IFN_RAWMEMCHR internal function.  */
    3404              : 
    3405              : void
    3406            0 : expand_RAWMEMCHR (internal_fn, gcall *stmt)
    3407              : {
    3408            0 :   expand_operand ops[3];
    3409              : 
    3410            0 :   tree lhs = gimple_call_lhs (stmt);
    3411            0 :   if (!lhs)
    3412            0 :     return;
    3413            0 :   machine_mode lhs_mode = TYPE_MODE (TREE_TYPE (lhs));
    3414            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3415            0 :   create_call_lhs_operand (&ops[0], lhs_rtx, lhs_mode);
    3416              : 
    3417            0 :   tree mem = gimple_call_arg (stmt, 0);
    3418            0 :   rtx mem_rtx = get_memory_rtx (mem, NULL, false);
    3419            0 :   create_fixed_operand (&ops[1], mem_rtx);
    3420              : 
    3421            0 :   tree pattern = gimple_call_arg (stmt, 1);
    3422            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (pattern));
    3423            0 :   rtx pattern_rtx = expand_normal (pattern);
    3424            0 :   create_input_operand (&ops[2], pattern_rtx, mode);
    3425              : 
    3426            0 :   insn_code icode = direct_optab_handler (rawmemchr_optab, mode);
    3427              : 
    3428            0 :   expand_insn (icode, 3, ops);
    3429            0 :   assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    3430              : }
    3431              : 
    3432              : /* Expand the IFN_UNIQUE function according to its first argument.  */
    3433              : 
    3434              : static void
    3435            0 : expand_UNIQUE (internal_fn, gcall *stmt)
    3436              : {
    3437            0 :   rtx pattern = NULL_RTX;
    3438            0 :   enum ifn_unique_kind kind
    3439            0 :     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (stmt, 0));
    3440              : 
    3441            0 :   switch (kind)
    3442              :     {
    3443            0 :     default:
    3444            0 :       gcc_unreachable ();
    3445              : 
    3446            0 :     case IFN_UNIQUE_UNSPEC:
    3447            0 :       if (targetm.have_unique ())
    3448            0 :         pattern = targetm.gen_unique ();
    3449              :       break;
    3450              : 
    3451            0 :     case IFN_UNIQUE_OACC_FORK:
    3452            0 :     case IFN_UNIQUE_OACC_JOIN:
    3453            0 :       if (targetm.have_oacc_fork () && targetm.have_oacc_join ())
    3454              :         {
    3455            0 :           tree lhs = gimple_call_lhs (stmt);
    3456            0 :           rtx target = const0_rtx;
    3457              : 
    3458            0 :           if (lhs)
    3459            0 :             target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3460              : 
    3461            0 :           rtx data_dep = expand_normal (gimple_call_arg (stmt, 1));
    3462            0 :           rtx axis = expand_normal (gimple_call_arg (stmt, 2));
    3463              : 
    3464            0 :           if (kind == IFN_UNIQUE_OACC_FORK)
    3465            0 :             pattern = targetm.gen_oacc_fork (target, data_dep, axis);
    3466              :           else
    3467            0 :             pattern = targetm.gen_oacc_join (target, data_dep, axis);
    3468              :         }
    3469              :       else
    3470            0 :         gcc_unreachable ();
    3471              :       break;
    3472              :     }
    3473              : 
    3474            0 :   if (pattern)
    3475            0 :     emit_insn (pattern);
    3476            0 : }
    3477              : 
    3478              : /* Expand the IFN_DEFERRED_INIT function:
    3479              :    LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, NAME of the DECL);
    3480              : 
    3481              :    Initialize the LHS with zero/pattern according to its second argument
    3482              :    INIT_TYPE:
    3483              :    if INIT_TYPE is AUTO_INIT_ZERO, use zeroes to initialize;
    3484              :    if INIT_TYPE is AUTO_INIT_PATTERN, use 0xFE byte-repeatable pattern
    3485              :      to initialize;
    3486              :    The LHS variable is initialized including paddings.
    3487              :    The reasons to choose 0xFE for pattern initialization are:
    3488              :      1. It is a non-canonical virtual address on x86_64, and at the
    3489              :         high end of the i386 kernel address space.
    3490              :      2. It is a very large float value (-1.694739530317379e+38).
    3491              :      3. It is also an unusual number for integers.  */
    3492              : #define INIT_PATTERN_VALUE  0xFE
    3493              : static void
    3494        40607 : expand_DEFERRED_INIT (internal_fn, gcall *stmt)
    3495              : {
    3496        40607 :   tree lhs = gimple_call_lhs (stmt);
    3497        40607 :   tree var_size = gimple_call_arg (stmt, 0);
    3498        40607 :   enum auto_init_type init_type
    3499        40607 :     = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
    3500        40607 :   bool reg_lhs = true;
    3501              : 
    3502        40607 :   tree var_type = TREE_TYPE (lhs);
    3503        40607 :   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
    3504              : 
    3505        40607 :   if (TREE_CODE (lhs) == SSA_NAME)
    3506              :     reg_lhs = true;
    3507              :   else
    3508              :     {
    3509              :       tree lhs_base = lhs;
    3510        27660 :       while (handled_component_p (lhs_base))
    3511            4 :         lhs_base = TREE_OPERAND (lhs_base, 0);
    3512        27656 :       reg_lhs = (mem_ref_refers_to_non_mem_p (lhs_base)
    3513        27656 :                  || non_mem_decl_p (lhs_base));
    3514              :       /* If this expands to a register and the underlying decl is wrapped in
    3515              :          a MEM_REF that just serves as an access type change expose the decl
    3516              :          if it is of correct size.  This avoids a situation as in PR103271
    3517              :          if the target does not support a direct move to the registers mode.  */
    3518              :       if (reg_lhs
    3519         1832 :           && TREE_CODE (lhs_base) == MEM_REF
    3520            4 :           && TREE_CODE (TREE_OPERAND (lhs_base, 0)) == ADDR_EXPR
    3521            4 :           && DECL_P (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))
    3522            4 :           && integer_zerop (TREE_OPERAND (lhs_base, 1))
    3523            4 :           && tree_fits_uhwi_p (var_size)
    3524            4 :           && tree_int_cst_equal
    3525            4 :                (var_size,
    3526            4 :                 DECL_SIZE_UNIT (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))))
    3527              :         {
    3528            4 :           lhs = TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0);
    3529            4 :           var_type = TREE_TYPE (lhs);
    3530              :         }
    3531              :     }
    3532              : 
    3533        27656 :   if (!reg_lhs)
    3534              :     {
    3535              :       /* If the variable is not in register, expand to a memset
    3536              :          to initialize it.  */
    3537        25824 :       mark_addressable (lhs);
    3538        25824 :       tree var_addr = build_fold_addr_expr (lhs);
    3539              : 
    3540        25824 :       tree value = ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN)
    3541        25824 :                     ? build_int_cst (integer_type_node,
    3542              :                                      INIT_PATTERN_VALUE)
    3543        25747 :                     : integer_zero_node;
    3544        51648 :       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
    3545              :                                      3, var_addr, value, var_size);
    3546              :       /* Expand this memset call.  */
    3547        25824 :       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
    3548              :     }
    3549              :   else
    3550              :     {
    3551              :       /* If this variable is in a register use expand_assignment.
    3552              :          For boolean scalars force zero-init.  */
    3553        14783 :       tree init;
    3554        14783 :       scalar_int_mode var_mode;
    3555        14783 :       if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE
    3556        14410 :           && tree_fits_uhwi_p (var_size)
    3557        14410 :           && ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN
    3558        14324 :               || !is_gimple_reg_type (var_type))
    3559         1918 :           && int_mode_for_size (tree_to_uhwi (var_size) * BITS_PER_UNIT,
    3560        14788 :                                 0).exists (&var_mode)
    3561        16701 :           && have_insn_for (SET, var_mode))
    3562              :         {
    3563         1913 :           unsigned HOST_WIDE_INT total_bytes = tree_to_uhwi (var_size);
    3564         1913 :           unsigned char *buf = XALLOCAVEC (unsigned char, total_bytes);
    3565         1913 :           memset (buf, ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN
    3566              :                         ? INIT_PATTERN_VALUE : 0), total_bytes);
    3567         1913 :           tree itype
    3568         1913 :             = build_nonstandard_integer_type (total_bytes * BITS_PER_UNIT, 1);
    3569         1913 :           wide_int w = wi::from_buffer (buf, total_bytes);
    3570         1913 :           init = wide_int_to_tree (itype, w);
    3571              :           /* Pun the LHS to make sure its type has constant size
    3572              :              unless it is an SSA name where that's already known.  */
    3573         1913 :           if (TREE_CODE (lhs) != SSA_NAME)
    3574         1832 :             lhs = build1 (VIEW_CONVERT_EXPR, itype, lhs);
    3575              :           else
    3576           81 :             init = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), init);
    3577         1913 :         }
    3578              :       else
    3579              :         /* Use zero-init also for variable-length sizes.  */
    3580        12870 :         init = build_zero_cst (var_type);
    3581              : 
    3582        14783 :       expand_assignment (lhs, init, false);
    3583              :     }
    3584        40607 : }
    3585              : 
    3586              : /* Expand the IFN_ACCESS_WITH_SIZE function:
    3587              :    ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE,
    3588              :                      TYPE_OF_SIZE + ACCESS_MODE, TYPE_SIZE_UNIT for element)
    3589              :    which returns the REF_TO_OBJ same as the 1st argument;
    3590              : 
    3591              :    1st argument REF_TO_OBJ: The reference to the object;
    3592              :    2nd argument REF_TO_SIZE: The reference to the size of the object,
    3593              :    3rd argument TYPE_OF_SIZE + ACCESS_MODE: An integer constant with a pointer
    3594              :      TYPE.
    3595              :      The pointee TYPE of the pointer TYPE is the TYPE of the object referenced
    3596              :         by REF_TO_SIZE.
    3597              :      The integer constant value represents the ACCESS_MODE:
    3598              :         0: none
    3599              :         1: read_only
    3600              :         2: write_only
    3601              :         3: read_write
    3602              : 
    3603              :    4th argument: The TYPE_SIZE_UNIT of the element TYPE of the array.
    3604              : 
    3605              :    Both the return type and the type of the first argument of this
    3606              :    function have been converted from the incomplete array type to
    3607              :    the corresponding pointer type.
    3608              : 
    3609              :    For each call to a .ACCESS_WITH_SIZE, replace it with its 1st argument.  */
    3610              : 
    3611              : static void
    3612          521 : expand_ACCESS_WITH_SIZE (internal_fn, gcall *stmt)
    3613              : {
    3614          521 :   tree lhs = gimple_call_lhs (stmt);
    3615          521 :   tree ref_to_obj = gimple_call_arg (stmt, 0);
    3616          521 :   if (lhs)
    3617          521 :     expand_assignment (lhs, ref_to_obj, false);
    3618          521 : }
    3619              : 
    3620              : /* The size of an OpenACC compute dimension.  */
    3621              : 
    3622              : static void
    3623         5695 : expand_GOACC_DIM_SIZE (internal_fn, gcall *stmt)
    3624              : {
    3625         5695 :   tree lhs = gimple_call_lhs (stmt);
    3626              : 
    3627         5695 :   if (!lhs)
    3628              :     return;
    3629              : 
    3630         5695 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3631         5695 :   if (targetm.have_oacc_dim_size ())
    3632              :     {
    3633            0 :       rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
    3634              :                              VOIDmode, EXPAND_NORMAL);
    3635            0 :       emit_insn (targetm.gen_oacc_dim_size (target, dim));
    3636              :     }
    3637              :   else
    3638         5695 :     emit_move_insn (target, GEN_INT (1));
    3639              : }
    3640              : 
    3641              : /* The position of an OpenACC execution engine along one compute axis.  */
    3642              : 
    3643              : static void
    3644         4567 : expand_GOACC_DIM_POS (internal_fn, gcall *stmt)
    3645              : {
    3646         4567 :   tree lhs = gimple_call_lhs (stmt);
    3647              : 
    3648         4567 :   if (!lhs)
    3649              :     return;
    3650              : 
    3651         4567 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3652         4567 :   if (targetm.have_oacc_dim_pos ())
    3653              :     {
    3654            0 :       rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
    3655              :                              VOIDmode, EXPAND_NORMAL);
    3656            0 :       emit_insn (targetm.gen_oacc_dim_pos (target, dim));
    3657              :     }
    3658              :   else
    3659         4567 :     emit_move_insn (target, const0_rtx);
    3660              : }
    3661              : 
    3662              : /* This is expanded by oacc_device_lower pass.  */
    3663              : 
    3664              : static void
    3665            0 : expand_GOACC_LOOP (internal_fn, gcall *)
    3666              : {
    3667            0 :   gcc_unreachable ();
    3668              : }
    3669              : 
    3670              : /* This is expanded by oacc_device_lower pass.  */
    3671              : 
    3672              : static void
    3673            0 : expand_GOACC_REDUCTION (internal_fn, gcall *)
    3674              : {
    3675            0 :   gcc_unreachable ();
    3676              : }
    3677              : 
    3678              : /* This is expanded by oacc_device_lower pass.  */
    3679              : 
    3680              : static void
    3681            0 : expand_GOACC_TILE (internal_fn, gcall *)
    3682              : {
    3683            0 :   gcc_unreachable ();
    3684              : }
    3685              : 
    3686              : /* Set errno to EDOM.  */
    3687              : 
    3688              : static void
    3689            0 : expand_SET_EDOM (internal_fn, gcall *)
    3690              : {
    3691              : #ifdef TARGET_EDOM
    3692              : #ifdef GEN_ERRNO_RTX
    3693              :   rtx errno_rtx = GEN_ERRNO_RTX;
    3694              : #else
    3695              :   rtx errno_rtx = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
    3696              : #endif
    3697              :   emit_move_insn (errno_rtx,
    3698              :                   gen_int_mode (TARGET_EDOM, GET_MODE (errno_rtx)));
    3699              : #else
    3700            0 :   gcc_unreachable ();
    3701              : #endif
    3702              : }
    3703              : 
    3704              : /* Expand atomic bit test and set.  */
    3705              : 
    3706              : static void
    3707          146 : expand_ATOMIC_BIT_TEST_AND_SET (internal_fn, gcall *call)
    3708              : {
    3709          146 :   expand_ifn_atomic_bit_test_and (call);
    3710          146 : }
    3711              : 
    3712              : /* Expand atomic bit test and complement.  */
    3713              : 
    3714              : static void
    3715          146 : expand_ATOMIC_BIT_TEST_AND_COMPLEMENT (internal_fn, gcall *call)
    3716              : {
    3717          146 :   expand_ifn_atomic_bit_test_and (call);
    3718          146 : }
    3719              : 
    3720              : /* Expand atomic bit test and reset.  */
    3721              : 
    3722              : static void
    3723          135 : expand_ATOMIC_BIT_TEST_AND_RESET (internal_fn, gcall *call)
    3724              : {
    3725          135 :   expand_ifn_atomic_bit_test_and (call);
    3726          135 : }
    3727              : 
    3728              : /* Expand atomic bit test and set.  */
    3729              : 
    3730              : static void
    3731        13951 : expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call)
    3732              : {
    3733        13951 :   expand_ifn_atomic_compare_exchange (call);
    3734        13951 : }
    3735              : 
    3736              : /* Expand atomic add fetch and cmp with 0.  */
    3737              : 
    3738              : static void
    3739          946 : expand_ATOMIC_ADD_FETCH_CMP_0 (internal_fn, gcall *call)
    3740              : {
    3741          946 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3742          946 : }
    3743              : 
    3744              : /* Expand atomic sub fetch and cmp with 0.  */
    3745              : 
    3746              : static void
    3747          738 : expand_ATOMIC_SUB_FETCH_CMP_0 (internal_fn, gcall *call)
    3748              : {
    3749          738 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3750          738 : }
    3751              : 
    3752              : /* Expand atomic and fetch and cmp with 0.  */
    3753              : 
    3754              : static void
    3755          176 : expand_ATOMIC_AND_FETCH_CMP_0 (internal_fn, gcall *call)
    3756              : {
    3757          176 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3758          176 : }
    3759              : 
    3760              : /* Expand atomic or fetch and cmp with 0.  */
    3761              : 
    3762              : static void
    3763          112 : expand_ATOMIC_OR_FETCH_CMP_0 (internal_fn, gcall *call)
    3764              : {
    3765          112 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3766          112 : }
    3767              : 
    3768              : /* Expand atomic xor fetch and cmp with 0.  */
    3769              : 
    3770              : static void
    3771          176 : expand_ATOMIC_XOR_FETCH_CMP_0 (internal_fn, gcall *call)
    3772              : {
    3773          176 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3774          176 : }
    3775              : 
    3776              : /* Expand LAUNDER to assignment, lhs = arg0.  */
    3777              : 
    3778              : static void
    3779           29 : expand_LAUNDER (internal_fn, gcall *call)
    3780              : {
    3781           29 :   tree lhs = gimple_call_lhs (call);
    3782              : 
    3783           29 :   if (!lhs)
    3784              :     return;
    3785              : 
    3786           28 :   expand_assignment (lhs, gimple_call_arg (call, 0), false);
    3787              : }
    3788              : 
    3789              : /* Expand {MASK_,}SCATTER_STORE{S,U} call CALL using optab OPTAB.  */
    3790              : 
    3791              : static void
    3792            0 : expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
    3793              : {
    3794            0 :   internal_fn ifn = gimple_call_internal_fn (stmt);
    3795            0 :   int rhs_index = internal_fn_stored_value_index (ifn);
    3796            0 :   tree base = gimple_call_arg (stmt, 0);
    3797            0 :   tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
    3798            0 :   tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
    3799            0 :   tree rhs = gimple_call_arg (stmt, rhs_index);
    3800              : 
    3801            0 :   rtx base_rtx = expand_normal (base);
    3802            0 :   rtx offset_rtx = expand_normal (offset);
    3803            0 :   HOST_WIDE_INT scale_int = tree_to_shwi (scale);
    3804            0 :   rtx rhs_rtx = expand_normal (rhs);
    3805              : 
    3806            0 :   class expand_operand ops[8];
    3807            0 :   int i = 0;
    3808            0 :   create_address_operand (&ops[i++], base_rtx);
    3809            0 :   create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
    3810            0 :   create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
    3811            0 :   create_integer_operand (&ops[i++], scale_int);
    3812            0 :   create_input_operand (&ops[i++], rhs_rtx, TYPE_MODE (TREE_TYPE (rhs)));
    3813            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3814              : 
    3815            0 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (rhs)),
    3816            0 :                                            TYPE_MODE (TREE_TYPE (offset)));
    3817            0 :   expand_insn (icode, i, ops);
    3818            0 : }
    3819              : 
    3820              : /* Expand {MASK_,}GATHER_LOAD call CALL using optab OPTAB.  */
    3821              : 
    3822              : static void
    3823            0 : expand_gather_load_optab_fn (internal_fn ifn, gcall *stmt, direct_optab optab)
    3824              : {
    3825            0 :   tree lhs = gimple_call_lhs (stmt);
    3826            0 :   tree base = gimple_call_arg (stmt, 0);
    3827            0 :   tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
    3828            0 :   tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
    3829              : 
    3830            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3831            0 :   rtx base_rtx = expand_normal (base);
    3832            0 :   rtx offset_rtx = expand_normal (offset);
    3833            0 :   HOST_WIDE_INT scale_int = tree_to_shwi (scale);
    3834              : 
    3835            0 :   int i = 0;
    3836            0 :   class expand_operand ops[9];
    3837            0 :   create_call_lhs_operand (&ops[i++], lhs_rtx, TYPE_MODE (TREE_TYPE (lhs)));
    3838            0 :   create_address_operand (&ops[i++], base_rtx);
    3839            0 :   create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
    3840            0 :   create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
    3841            0 :   create_integer_operand (&ops[i++], scale_int);
    3842            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3843            0 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)),
    3844            0 :                                            TYPE_MODE (TREE_TYPE (offset)));
    3845            0 :   expand_insn (icode, i, ops);
    3846            0 :   assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    3847            0 : }
    3848              : 
    3849              : /* Expand MASK_LEN_STRIDED_LOAD call CALL by optab OPTAB.  */
    3850              : 
    3851              : static void
    3852            0 : expand_strided_load_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
    3853              :                               direct_optab optab)
    3854              : {
    3855            0 :   tree lhs = gimple_call_lhs (stmt);
    3856            0 :   tree base = gimple_call_arg (stmt, 0);
    3857            0 :   tree stride = gimple_call_arg (stmt, 1);
    3858              : 
    3859            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3860            0 :   rtx base_rtx = expand_normal (base);
    3861            0 :   rtx stride_rtx = expand_normal (stride);
    3862              : 
    3863            0 :   unsigned i = 0;
    3864            0 :   class expand_operand ops[7];
    3865            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
    3866              : 
    3867            0 :   create_output_operand (&ops[i++], lhs_rtx, mode);
    3868            0 :   create_address_operand (&ops[i++], base_rtx);
    3869            0 :   create_address_operand (&ops[i++], stride_rtx);
    3870              : 
    3871            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3872            0 :   expand_insn (direct_optab_handler (optab, mode), i, ops);
    3873              : 
    3874            0 :   if (!rtx_equal_p (lhs_rtx, ops[0].value))
    3875            0 :     emit_move_insn (lhs_rtx, ops[0].value);
    3876            0 : }
    3877              : 
    3878              : /* Expand MASK_LEN_STRIDED_STORE call CALL by optab OPTAB.  */
    3879              : 
    3880              : static void
    3881            0 : expand_strided_store_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
    3882              :                                direct_optab optab)
    3883              : {
    3884            0 :   internal_fn fn = gimple_call_internal_fn (stmt);
    3885            0 :   int rhs_index = internal_fn_stored_value_index (fn);
    3886              : 
    3887            0 :   tree base = gimple_call_arg (stmt, 0);
    3888            0 :   tree stride = gimple_call_arg (stmt, 1);
    3889            0 :   tree rhs = gimple_call_arg (stmt, rhs_index);
    3890              : 
    3891            0 :   rtx base_rtx = expand_normal (base);
    3892            0 :   rtx stride_rtx = expand_normal (stride);
    3893            0 :   rtx rhs_rtx = expand_normal (rhs);
    3894              : 
    3895            0 :   unsigned i = 0;
    3896            0 :   class expand_operand ops[6];
    3897            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (rhs));
    3898              : 
    3899            0 :   create_address_operand (&ops[i++], base_rtx);
    3900            0 :   create_address_operand (&ops[i++], stride_rtx);
    3901            0 :   create_input_operand (&ops[i++], rhs_rtx, mode);
    3902              : 
    3903            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3904            0 :   expand_insn (direct_optab_handler (optab, mode), i, ops);
    3905            0 : }
    3906              : 
    3907              : /* Helper for expand_DIVMOD.  Return true if the sequence starting with
    3908              :    INSN contains any call insns or insns with {,U}{DIV,MOD} rtxes.  */
    3909              : 
    3910              : static bool
    3911          838 : contains_call_div_mod (rtx_insn *insn)
    3912              : {
    3913          838 :   subrtx_iterator::array_type array;
    3914         4821 :   for (; insn; insn = NEXT_INSN (insn))
    3915         4821 :     if (CALL_P (insn))
    3916              :       return true;
    3917         3983 :     else if (INSN_P (insn))
    3918        17804 :       FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
    3919        13821 :         switch (GET_CODE (*iter))
    3920              :           {
    3921            0 :           case CALL:
    3922            0 :           case DIV:
    3923            0 :           case UDIV:
    3924            0 :           case MOD:
    3925            0 :           case UMOD:
    3926            0 :             return true;
    3927        13821 :           default:
    3928        13821 :             break;
    3929              :           }
    3930              :   return false;
    3931          838 :  }
    3932              : 
    3933              : /* Expand DIVMOD() using:
    3934              :  a) optab handler for udivmod/sdivmod if it is available.
    3935              :  b) If optab_handler doesn't exist, generate call to
    3936              :     target-specific divmod libfunc.  */
    3937              : 
    3938              : static void
    3939        11511 : expand_DIVMOD (internal_fn, gcall *call_stmt)
    3940              : {
    3941        11511 :   tree lhs = gimple_call_lhs (call_stmt);
    3942        11511 :   tree arg0 = gimple_call_arg (call_stmt, 0);
    3943        11511 :   tree arg1 = gimple_call_arg (call_stmt, 1);
    3944              : 
    3945        11511 :   gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
    3946        11511 :   tree type = TREE_TYPE (TREE_TYPE (lhs));
    3947        11511 :   machine_mode mode = TYPE_MODE (type);
    3948        11511 :   bool unsignedp = TYPE_UNSIGNED (type);
    3949        11511 :   optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab;
    3950              : 
    3951        11511 :   rtx op0 = expand_normal (arg0);
    3952        11511 :   rtx op1 = expand_normal (arg1);
    3953        11511 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3954              : 
    3955        11511 :   rtx quotient = NULL_RTX, remainder = NULL_RTX;
    3956        11511 :   rtx_insn *insns = NULL;
    3957              : 
    3958        11511 :   if (TREE_CODE (arg1) == INTEGER_CST)
    3959              :     {
    3960              :       /* For DIVMOD by integral constants, there could be efficient code
    3961              :          expanded inline e.g. using shifts and plus/minus.  Try to expand
    3962              :          the division and modulo and if it emits any library calls or any
    3963              :          {,U}{DIV,MOD} rtxes throw it away and use a divmod optab or
    3964              :          divmod libcall.  */
    3965         1182 :       scalar_int_mode int_mode;
    3966         1182 :       if (remainder == NULL_RTX
    3967         1182 :           && optimize
    3968         1182 :           && CONST_INT_P (op1)
    3969         1178 :           && !pow2p_hwi (INTVAL (op1))
    3970         2356 :           && is_int_mode (TYPE_MODE (type), &int_mode)
    3971         1342 :           && GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD
    3972         1178 :           && optab_handler (and_optab, word_mode) != CODE_FOR_nothing
    3973         1178 :           && optab_handler (add_optab, word_mode) != CODE_FOR_nothing
    3974         1178 :           && optimize_insn_for_speed_p ())
    3975              :         {
    3976         1178 :           rtx_insn *last = get_last_insn ();
    3977         1178 :           remainder = NULL_RTX;
    3978         3534 :           quotient = expand_doubleword_divmod (int_mode, op0, op1, &remainder,
    3979         1178 :                                                TYPE_UNSIGNED (type));
    3980         1178 :           if (quotient != NULL_RTX)
    3981              :             {
    3982          344 :               if (optab_handler (mov_optab, int_mode) != CODE_FOR_nothing)
    3983              :                 {
    3984          344 :                   rtx_insn *move = emit_move_insn (quotient, quotient);
    3985          688 :                   set_dst_reg_note (move, REG_EQUAL,
    3986          344 :                                     gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
    3987              :                                                     ? UDIV : DIV, int_mode,
    3988              :                                                     copy_rtx (op0), op1),
    3989              :                                     quotient);
    3990          344 :                   move = emit_move_insn (remainder, remainder);
    3991          688 :                   set_dst_reg_note (move, REG_EQUAL,
    3992          344 :                                     gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
    3993              :                                                     ? UMOD : MOD, int_mode,
    3994              :                                                     copy_rtx (op0), op1),
    3995              :                                     quotient);
    3996              :                 }
    3997              :             }
    3998              :           else
    3999          834 :             delete_insns_since (last);
    4000              :         }
    4001              : 
    4002         1182 :       if (remainder == NULL_RTX)
    4003              :         {
    4004          838 :           struct separate_ops ops;
    4005          838 :           ops.code = TRUNC_DIV_EXPR;
    4006          838 :           ops.type = type;
    4007          838 :           ops.op0 = make_tree (ops.type, op0);
    4008          838 :           ops.op1 = arg1;
    4009          838 :           ops.op2 = NULL_TREE;
    4010          838 :           ops.location = gimple_location (call_stmt);
    4011          838 :           start_sequence ();
    4012          838 :           quotient = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    4013          838 :           if (contains_call_div_mod (get_insns ()))
    4014          838 :             quotient = NULL_RTX;
    4015              :           else
    4016              :             {
    4017            0 :               ops.code = TRUNC_MOD_EXPR;
    4018            0 :               remainder = expand_expr_real_2 (&ops, NULL_RTX, mode,
    4019              :                                               EXPAND_NORMAL);
    4020            0 :               if (contains_call_div_mod (get_insns ()))
    4021            0 :                 remainder = NULL_RTX;
    4022              :             }
    4023          838 :           if (remainder)
    4024            0 :             insns = get_insns ();
    4025          838 :           end_sequence ();
    4026              :         }
    4027              :     }
    4028              : 
    4029        11511 :   if (remainder)
    4030          344 :     emit_insn (insns);
    4031              : 
    4032              :   /* Check if optab_handler exists for divmod_optab for given mode.  */
    4033        11167 :   else if (optab_handler (tab, mode) != CODE_FOR_nothing)
    4034              :     {
    4035        10275 :       quotient = gen_reg_rtx (mode);
    4036        10275 :       remainder = gen_reg_rtx (mode);
    4037        10275 :       expand_twoval_binop (tab, op0, op1, quotient, remainder, unsignedp);
    4038              :     }
    4039              : 
    4040              :   /* Generate call to divmod libfunc if it exists.  */
    4041          892 :   else if (rtx libfunc = optab_libfunc (tab, mode))
    4042          892 :     targetm.expand_divmod_libfunc (libfunc, mode, op0, op1,
    4043              :                                    &quotient, &remainder);
    4044              : 
    4045              :   else
    4046            0 :     gcc_unreachable ();
    4047              : 
    4048              :   /* Wrap the return value (quotient, remainder) within COMPLEX_EXPR.  */
    4049        23022 :   expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
    4050        11511 :                        make_tree (TREE_TYPE (arg0), quotient),
    4051        11511 :                        make_tree (TREE_TYPE (arg1), remainder)),
    4052              :                target, VOIDmode, EXPAND_NORMAL);
    4053        11511 : }
    4054              : 
    4055              : /* Expand a NOP.  */
    4056              : 
    4057              : static void
    4058            1 : expand_NOP (internal_fn, gcall *)
    4059              : {
    4060              :   /* Nothing.  But it shouldn't really prevail.  */
    4061            1 : }
    4062              : 
    4063              : /* Coroutines, all should have been processed at this stage.  */
    4064              : 
    4065              : static void
    4066            0 : expand_CO_FRAME (internal_fn, gcall *)
    4067              : {
    4068            0 :   gcc_unreachable ();
    4069              : }
    4070              : 
    4071              : static void
    4072            0 : expand_CO_YIELD (internal_fn, gcall *)
    4073              : {
    4074            0 :   gcc_unreachable ();
    4075              : }
    4076              : 
    4077              : static void
    4078            0 : expand_CO_SUSPN (internal_fn, gcall *)
    4079              : {
    4080            0 :   gcc_unreachable ();
    4081              : }
    4082              : 
    4083              : static void
    4084            0 : expand_CO_ACTOR (internal_fn, gcall *)
    4085              : {
    4086            0 :   gcc_unreachable ();
    4087              : }
    4088              : 
    4089              : /* Expand a call to FN using the operands in STMT.  FN has a single
    4090              :    output operand and NARGS input operands.  */
    4091              : 
    4092              : static void
    4093        76671 : expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
    4094              :                         unsigned int nargs)
    4095              : {
    4096        76671 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4097        76671 :   insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
    4098        76671 :   expand_fn_using_insn (stmt, icode, 1, nargs);
    4099        76671 : }
    4100              : 
    4101              : /* Expand WHILE_ULT call STMT using optab OPTAB.  */
    4102              : 
    4103              : static void
    4104            0 : expand_while_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
    4105              : {
    4106            0 :   expand_operand ops[4];
    4107            0 :   tree rhs_type[2];
    4108              : 
    4109            0 :   tree lhs = gimple_call_lhs (stmt);
    4110            0 :   tree lhs_type = TREE_TYPE (lhs);
    4111            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    4112            0 :   create_call_lhs_operand (&ops[0], lhs_rtx, TYPE_MODE (lhs_type));
    4113              : 
    4114            0 :   for (unsigned int i = 0; i < 2; ++i)
    4115              :     {
    4116            0 :       tree rhs = gimple_call_arg (stmt, i);
    4117            0 :       rhs_type[i] = TREE_TYPE (rhs);
    4118            0 :       rtx rhs_rtx = expand_normal (rhs);
    4119            0 :       create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type[i]));
    4120              :     }
    4121              : 
    4122            0 :   int opcnt;
    4123            0 :   if (!VECTOR_MODE_P (TYPE_MODE (lhs_type)))
    4124              :     {
    4125              :       /* When the mask is an integer mode the exact vector length may not
    4126              :          be clear to the backend, so we pass it in operand[3].
    4127              :          Use the vector in arg2 for the most reliable intended size.  */
    4128            0 :       tree type = TREE_TYPE (gimple_call_arg (stmt, 2));
    4129            0 :       create_integer_operand (&ops[3], TYPE_VECTOR_SUBPARTS (type));
    4130            0 :       opcnt = 4;
    4131              :     }
    4132              :   else
    4133              :     /* The mask has a vector type so the length operand is unnecessary.  */
    4134              :     opcnt = 3;
    4135              : 
    4136            0 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (rhs_type[0]),
    4137            0 :                                            TYPE_MODE (lhs_type));
    4138              : 
    4139            0 :   expand_insn (icode, opcnt, ops);
    4140            0 :   assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    4141            0 : }
    4142              : 
    4143              : /* Expand a call to a convert-like optab using the operands in STMT.
    4144              :    FN has a single output operand and NARGS input operands.  */
    4145              : 
    4146              : static void
    4147          481 : expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab,
    4148              :                          unsigned int nargs)
    4149              : {
    4150          481 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4151          481 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (types.first),
    4152          481 :                                           TYPE_MODE (types.second));
    4153          481 :   expand_fn_using_insn (stmt, icode, 1, nargs);
    4154          481 : }
    4155              : 
    4156              : /* Expand CRC call STMT.  */
    4157              : 
    4158              : static void
    4159          238 : expand_crc_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab)
    4160              : {
    4161          238 :   tree lhs = gimple_call_lhs (stmt);
    4162          238 :   tree rhs1 = gimple_call_arg (stmt, 0); // crc
    4163          238 :   tree rhs2 = gimple_call_arg (stmt, 1); // data
    4164          238 :   tree rhs3 = gimple_call_arg (stmt, 2); // polynomial
    4165              : 
    4166          238 :   tree result_type = TREE_TYPE (lhs);
    4167          238 :   tree data_type = TREE_TYPE (rhs2);
    4168              : 
    4169          238 :   gcc_assert (TYPE_MODE (result_type) >= TYPE_MODE (data_type));
    4170              : 
    4171          238 :   rtx dest = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    4172          238 :   rtx crc = expand_normal (rhs1);
    4173          238 :   rtx data = expand_normal (rhs2);
    4174          238 :   rtx polynomial;
    4175          238 :   if (TREE_CODE (rhs3) != INTEGER_CST)
    4176              :     {
    4177            0 :       error ("third argument to %<crc%> builtins must be a constant");
    4178            0 :       polynomial = const0_rtx;
    4179              :     }
    4180              :   else
    4181          238 :     polynomial = convert_to_mode (TYPE_MODE (result_type), expand_normal (rhs3), 0);
    4182              : 
    4183              :   /* Use target specific expansion if it exists.
    4184              :      Otherwise, generate table-based CRC.  */
    4185          238 :   if (direct_internal_fn_supported_p (fn, tree_pair (data_type, result_type),
    4186              :                                       OPTIMIZE_FOR_SPEED))
    4187              :     {
    4188            3 :       class expand_operand ops[4];
    4189              : 
    4190            3 :       if (dump_file && (dump_flags & TDF_DETAILS))
    4191              :         {
    4192            0 :           fprintf (dump_file,
    4193              :                    ";; using optab for crc_%u_polynomial_"
    4194              :                    HOST_WIDE_INT_PRINT_HEX "\n",
    4195            0 :                    GET_MODE_BITSIZE (GET_MODE (dest)).to_constant (),
    4196            0 :                    TREE_INT_CST_LOW (rhs3));
    4197              :         }
    4198              : 
    4199            3 :       create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
    4200            3 :       create_input_operand (&ops[1], crc, TYPE_MODE (result_type));
    4201            3 :       create_input_operand (&ops[2], data, TYPE_MODE (data_type));
    4202            3 :       create_input_operand (&ops[3], polynomial, TYPE_MODE (result_type));
    4203            3 :       insn_code icode = convert_optab_handler (optab, TYPE_MODE (data_type),
    4204            3 :                                                TYPE_MODE (result_type));
    4205            3 :       expand_insn (icode, 4, ops);
    4206            3 :       assign_call_lhs (lhs, dest, &ops[0]);
    4207              :     }
    4208              :   else
    4209              :     {
    4210              :       /* We're bypassing all the operand conversions that are done in the
    4211              :          case when we get an icode, operands and pass that off to expand_insn.
    4212              : 
    4213              :          That path has special case handling for promoted return values which
    4214              :          we must emulate here (is the same kind of special treatment ever
    4215              :          needed for input arguments here?).
    4216              : 
    4217              :          In particular we do not want to store directly into a promoted
    4218              :          SUBREG destination, instead store into a suitably sized pseudo.  */
    4219          235 :       rtx orig_dest = dest;
    4220          235 :       if (SUBREG_P (dest) && SUBREG_PROMOTED_VAR_P (dest))
    4221            0 :         dest = gen_reg_rtx (GET_MODE (dest));
    4222              : 
    4223              :       /* If it's IFN_CRC generate bit-forward CRC.  */
    4224          235 :       if (fn == IFN_CRC)
    4225          116 :         expand_crc_table_based (dest, crc, data, polynomial,
    4226          116 :                                 TYPE_MODE (data_type));
    4227              :       else
    4228              :         /* If it's IFN_CRC_REV generate bit-reversed CRC.  */
    4229          119 :         expand_reversed_crc_table_based (dest, crc, data, polynomial,
    4230          119 :                                          TYPE_MODE (data_type));
    4231              : 
    4232              :       /* Now get the return value where it needs to be, taking care to
    4233              :          ensure it's promoted appropriately if the ABI demands it.
    4234              : 
    4235              :          Re-use assign_call_lhs to handle the details.  */
    4236          235 :       class expand_operand ops[4];
    4237          235 :       create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
    4238          235 :       ops[0].value = dest;
    4239          235 :       assign_call_lhs (lhs, orig_dest, &ops[0]);
    4240              :     }
    4241          238 : }
    4242              : 
    4243              : /* Expand .REDUC_SBOOL_{AND,IOR,XOR}.  */
    4244              : 
    4245              : static void
    4246           49 : expand_reduc_sbool_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab)
    4247              : {
    4248           49 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4249           49 :   insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
    4250              : 
    4251              :   /* Below copied from expand_fn_using_insn.  */
    4252              : 
    4253           49 :   gcc_assert (icode != CODE_FOR_nothing);
    4254              : 
    4255           49 :   expand_operand *ops = XALLOCAVEC (expand_operand, 3);
    4256           49 :   rtx lhs_rtx = NULL_RTX;
    4257           49 :   tree lhs = gimple_call_lhs (stmt);
    4258           49 :   if (lhs)
    4259           49 :     lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    4260           49 :   create_call_lhs_operand (&ops[0], lhs_rtx,
    4261           49 :                            insn_data[icode].operand[0].mode);
    4262              : 
    4263           49 :   tree rhs = gimple_call_arg (stmt, 0);
    4264           49 :   tree rhs_type = TREE_TYPE (rhs);
    4265           49 :   rtx rhs_rtx = expand_normal (rhs);
    4266           49 :   gcc_assert (VECTOR_BOOLEAN_TYPE_P (rhs_type));
    4267           49 :   create_input_operand (&ops[1], rhs_rtx, TYPE_MODE (rhs_type));
    4268           49 :   if (SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)))
    4269              :     {
    4270           24 :       rtx nunits = GEN_INT (TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ());
    4271           24 :       gcc_assert (insn_operand_matches (icode, 2, nunits));
    4272           24 :       create_input_operand (&ops[2], nunits, SImode);
    4273              :     }
    4274           73 :   expand_insn (icode, SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)) ? 3 : 2, ops);
    4275           49 :   if (lhs_rtx)
    4276           49 :     assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    4277           49 : }
    4278              : 
    4279              : /* Expanders for optabs that can use expand_direct_optab_fn.  */
    4280              : 
    4281              : #define expand_unary_optab_fn(FN, STMT, OPTAB) \
    4282              :   expand_direct_optab_fn (FN, STMT, OPTAB, 1)
    4283              : 
    4284              : #define expand_binary_optab_fn(FN, STMT, OPTAB) \
    4285              :   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
    4286              : 
    4287              : #define expand_ternary_optab_fn(FN, STMT, OPTAB) \
    4288              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4289              : 
    4290              : #define expand_cond_unary_optab_fn(FN, STMT, OPTAB) \
    4291              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4292              : 
    4293              : #define expand_cond_binary_optab_fn(FN, STMT, OPTAB) \
    4294              :   expand_direct_optab_fn (FN, STMT, OPTAB, 4)
    4295              : 
    4296              : #define expand_cond_ternary_optab_fn(FN, STMT, OPTAB) \
    4297              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4298              : 
    4299              : #define expand_cond_len_unary_optab_fn(FN, STMT, OPTAB) \
    4300              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4301              : 
    4302              : #define expand_cond_len_binary_optab_fn(FN, STMT, OPTAB) \
    4303              :   expand_direct_optab_fn (FN, STMT, OPTAB, 6)
    4304              : 
    4305              : #define expand_cond_len_ternary_optab_fn(FN, STMT, OPTAB) \
    4306              :   expand_direct_optab_fn (FN, STMT, OPTAB, 7)
    4307              : 
    4308              : #define expand_fold_extract_optab_fn(FN, STMT, OPTAB) \
    4309              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4310              : 
    4311              : #define expand_fold_len_extract_optab_fn(FN, STMT, OPTAB) \
    4312              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4313              : 
    4314              : #define expand_fold_left_optab_fn(FN, STMT, OPTAB) \
    4315              :   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
    4316              : 
    4317              : #define expand_mask_fold_left_optab_fn(FN, STMT, OPTAB) \
    4318              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4319              : 
    4320              : #define expand_mask_len_fold_left_optab_fn(FN, STMT, OPTAB) \
    4321              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4322              : 
    4323              : #define expand_check_ptrs_optab_fn(FN, STMT, OPTAB) \
    4324              :   expand_direct_optab_fn (FN, STMT, OPTAB, 4)
    4325              : 
    4326              : #define expand_select_vl_optab_fn(FN, STMT, OPTAB) \
    4327              :   expand_convert_optab_fn (FN, STMT, OPTAB, 3)
    4328              : 
    4329              : /* Expanders for optabs that can use expand_convert_optab_fn.  */
    4330              : 
    4331              : #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \
    4332              :   expand_convert_optab_fn (FN, STMT, OPTAB, 1)
    4333              : 
    4334              : #define expand_vec_extract_optab_fn(FN, STMT, OPTAB) \
    4335              :   expand_convert_optab_fn (FN, STMT, OPTAB, 2)
    4336              : 
    4337              : /* RETURN_TYPE and ARGS are a return type and argument list that are
    4338              :    in principle compatible with FN (which satisfies direct_internal_fn_p).
    4339              :    Return the types that should be used to determine whether the
    4340              :    target supports FN.  */
    4341              : 
    4342              : tree_pair
    4343         8327 : direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
    4344              : {
    4345         8327 :   const direct_internal_fn_info &info = direct_internal_fn (fn);
    4346         8327 :   tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
    4347         8327 :   tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
    4348         8327 :   return tree_pair (type0, type1);
    4349              : }
    4350              : 
    4351              : /* CALL is a call whose return type and arguments are in principle
    4352              :    compatible with FN (which satisfies direct_internal_fn_p).  Return the
    4353              :    types that should be used to determine whether the target supports FN.  */
    4354              : 
    4355              : tree_pair
    4356       138455 : direct_internal_fn_types (internal_fn fn, gcall *call)
    4357              : {
    4358       138455 :   const direct_internal_fn_info &info = direct_internal_fn (fn);
    4359       138455 :   tree op0 = (info.type0 < 0
    4360       138455 :               ? gimple_call_lhs (call)
    4361       136926 :               : gimple_call_arg (call, info.type0));
    4362       138455 :   tree op1 = (info.type1 < 0
    4363       138455 :               ? gimple_call_lhs (call)
    4364       138407 :               : gimple_call_arg (call, info.type1));
    4365       138455 :   return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1));
    4366              : }
    4367              : 
    4368              : /* Return true if OPTAB is supported for TYPES (whose modes should be
    4369              :    the same) when the optimization type is OPT_TYPE.  Used for simple
    4370              :    direct optabs.  */
    4371              : 
    4372              : static bool
    4373      4181576 : direct_optab_supported_p (direct_optab optab, tree_pair types,
    4374              :                           optimization_type opt_type)
    4375              : {
    4376      4181576 :   machine_mode mode = TYPE_MODE (types.first);
    4377      4181576 :   gcc_checking_assert (mode == TYPE_MODE (types.second));
    4378      4181576 :   return direct_optab_handler (optab, mode, opt_type) != CODE_FOR_nothing;
    4379              : }
    4380              : 
    4381              : /* Return true if OPTAB is supported for TYPES, where the first type
    4382              :    is the destination and the second type is the source.  Used for
    4383              :    convert optabs.  */
    4384              : 
    4385              : static bool
    4386       112788 : convert_optab_supported_p (convert_optab optab, tree_pair types,
    4387              :                            optimization_type opt_type)
    4388              : {
    4389       112788 :   return (convert_optab_handler (optab, TYPE_MODE (types.first),
    4390       112788 :                                  TYPE_MODE (types.second), opt_type)
    4391       112788 :           != CODE_FOR_nothing);
    4392              : }
    4393              : 
    4394              : /* Return true if load/store lanes optab OPTAB is supported for
    4395              :    array type TYPES.first when the optimization type is OPT_TYPE.  */
    4396              : 
    4397              : static bool
    4398            0 : multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
    4399              :                                 optimization_type opt_type)
    4400              : {
    4401            0 :   gcc_assert (TREE_CODE (types.first) == ARRAY_TYPE);
    4402            0 :   machine_mode imode = TYPE_MODE (types.first);
    4403            0 :   machine_mode vmode = TYPE_MODE (TREE_TYPE (types.first));
    4404            0 :   return (convert_optab_handler (optab, imode, vmode, opt_type)
    4405            0 :           != CODE_FOR_nothing);
    4406              : }
    4407              : 
    4408              : #define direct_unary_optab_supported_p direct_optab_supported_p
    4409              : #define direct_unary_convert_optab_supported_p convert_optab_supported_p
    4410              : #define direct_binary_optab_supported_p direct_optab_supported_p
    4411              : #define direct_ternary_optab_supported_p direct_optab_supported_p
    4412              : #define direct_cond_unary_optab_supported_p direct_optab_supported_p
    4413              : #define direct_cond_binary_optab_supported_p direct_optab_supported_p
    4414              : #define direct_cond_ternary_optab_supported_p direct_optab_supported_p
    4415              : #define direct_cond_len_unary_optab_supported_p direct_optab_supported_p
    4416              : #define direct_cond_len_binary_optab_supported_p direct_optab_supported_p
    4417              : #define direct_cond_len_ternary_optab_supported_p direct_optab_supported_p
    4418              : #define direct_crc_optab_supported_p convert_optab_supported_p
    4419              : #define direct_mask_load_optab_supported_p convert_optab_supported_p
    4420              : #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
    4421              : #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
    4422              : #define direct_gather_load_optab_supported_p convert_optab_supported_p
    4423              : #define direct_strided_load_optab_supported_p direct_optab_supported_p
    4424              : #define direct_len_load_optab_supported_p direct_optab_supported_p
    4425              : #define direct_mask_len_load_optab_supported_p convert_optab_supported_p
    4426              : #define direct_mask_store_optab_supported_p convert_optab_supported_p
    4427              : #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
    4428              : #define direct_mask_store_lanes_optab_supported_p multi_vector_optab_supported_p
    4429              : #define direct_vec_cond_mask_optab_supported_p convert_optab_supported_p
    4430              : #define direct_vec_cond_optab_supported_p convert_optab_supported_p
    4431              : #define direct_scatter_store_optab_supported_p convert_optab_supported_p
    4432              : #define direct_strided_store_optab_supported_p direct_optab_supported_p
    4433              : #define direct_len_store_optab_supported_p direct_optab_supported_p
    4434              : #define direct_mask_len_store_optab_supported_p convert_optab_supported_p
    4435              : #define direct_while_optab_supported_p convert_optab_supported_p
    4436              : #define direct_fold_extract_optab_supported_p direct_optab_supported_p
    4437              : #define direct_fold_len_extract_optab_supported_p direct_optab_supported_p
    4438              : #define direct_fold_left_optab_supported_p direct_optab_supported_p
    4439              : #define direct_mask_fold_left_optab_supported_p direct_optab_supported_p
    4440              : #define direct_mask_len_fold_left_optab_supported_p direct_optab_supported_p
    4441              : #define direct_check_ptrs_optab_supported_p direct_optab_supported_p
    4442              : #define direct_vec_set_optab_supported_p direct_optab_supported_p
    4443              : #define direct_vec_extract_optab_supported_p convert_optab_supported_p
    4444              : #define direct_reduc_sbool_optab_supported_p direct_optab_supported_p
    4445              : #define direct_select_vl_optab_supported_p convert_optab_supported_p
    4446              : 
    4447              : /* Return the optab used by internal function FN.  */
    4448              : 
    4449              : optab
    4450       283874 : direct_internal_fn_optab (internal_fn fn, tree_pair types)
    4451              : {
    4452       283874 :   switch (fn)
    4453              :     {
    4454              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
    4455              :     case IFN_##CODE: break;
    4456              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4457              :     case IFN_##CODE: return OPTAB##_optab;
    4458              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
    4459              :                                      UNSIGNED_OPTAB, TYPE)              \
    4460              :     case IFN_##CODE: return (TYPE_UNSIGNED (types.SELECTOR)             \
    4461              :                              ? UNSIGNED_OPTAB ## _optab                 \
    4462              :                              : SIGNED_OPTAB ## _optab);
    4463              : #include "internal-fn.def"
    4464              : 
    4465              :     case IFN_LAST:
    4466              :       break;
    4467              :     }
    4468            0 :   gcc_unreachable ();
    4469              : }
    4470              : 
    4471              : /* Return the optab used by internal function FN.  */
    4472              : 
    4473              : static optab
    4474       976116 : direct_internal_fn_optab (internal_fn fn)
    4475              : {
    4476       976116 :   switch (fn)
    4477              :     {
    4478              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
    4479              :     case IFN_##CODE: break;
    4480              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4481              :     case IFN_##CODE: return OPTAB##_optab;
    4482              : #include "internal-fn.def"
    4483              : 
    4484              :     case IFN_LAST:
    4485              :       break;
    4486              :     }
    4487            0 :   gcc_unreachable ();
    4488              : }
    4489              : 
    4490              : /* Return true if TYPE's mode has the same format as TYPE, and if there is
    4491              :    a 1:1 correspondence between the values that the mode can store and the
    4492              :    values that the type can store.  */
    4493              : 
    4494              : static bool
    4495      8740708 : type_strictly_matches_mode_p (const_tree type)
    4496              : {
    4497              :   /* The masked vector operations have both vector data operands and vector
    4498              :      boolean operands.  The vector data operands are expected to have a vector
    4499              :      mode,  but the vector boolean operands can be an integer mode rather than
    4500              :      a vector mode,  depending on how TARGET_VECTORIZE_GET_MASK_MODE is
    4501              :      defined.  PR116103.  */
    4502      1127808 :   if (VECTOR_BOOLEAN_TYPE_P (type)
    4503       258840 :       && SCALAR_INT_MODE_P (TYPE_MODE (type))
    4504      8830947 :       && TYPE_PRECISION (TREE_TYPE (type)) == 1)
    4505              :     return true;
    4506              : 
    4507      8650470 :   if (VECTOR_TYPE_P (type))
    4508      1037570 :     return VECTOR_MODE_P (TYPE_MODE (type));
    4509              : 
    4510      7612900 :   if (INTEGRAL_TYPE_P (type))
    4511      7204669 :     return type_has_mode_precision_p (type);
    4512              : 
    4513       408231 :   if (SCALAR_FLOAT_TYPE_P (type) || COMPLEX_FLOAT_TYPE_P (type))
    4514              :     return true;
    4515              : 
    4516              :   return false;
    4517              : }
    4518              : 
    4519              : /* Returns true if both types of TYPE_PAIR strictly match their modes,
    4520              :    else returns false.  */
    4521              : 
    4522              : static bool
    4523      4446344 : type_pair_strictly_matches_mode_p (tree_pair type_pair)
    4524              : {
    4525      4446344 :   return type_strictly_matches_mode_p (type_pair.first)
    4526      4446344 :     && type_strictly_matches_mode_p (type_pair.second);
    4527              : }
    4528              : 
    4529              : /* Return true if FN is supported for the types in TYPES when the
    4530              :    optimization type is OPT_TYPE.  The types are those associated with
    4531              :    the "type0" and "type1" fields of FN's direct_internal_fn_info
    4532              :    structure.  */
    4533              : 
    4534              : bool
    4535      4446344 : direct_internal_fn_supported_p (internal_fn fn, tree_pair types,
    4536              :                                 optimization_type opt_type)
    4537              : {
    4538      4446344 :   if (!type_pair_strictly_matches_mode_p (types))
    4539              :     return false;
    4540              : 
    4541      4294364 :   switch (fn)
    4542              :     {
    4543              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
    4544              :     case IFN_##CODE: break;
    4545              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4546              :     case IFN_##CODE: \
    4547              :       return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \
    4548              :                                                 opt_type);
    4549              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
    4550              :                                      UNSIGNED_OPTAB, TYPE)              \
    4551              :     case IFN_##CODE:                                                    \
    4552              :       {                                                                 \
    4553              :         optab which_optab = (TYPE_UNSIGNED (types.SELECTOR)             \
    4554              :                              ? UNSIGNED_OPTAB ## _optab                 \
    4555              :                              : SIGNED_OPTAB ## _optab);                 \
    4556              :         return direct_##TYPE##_optab_supported_p (which_optab, types,   \
    4557              :                                                   opt_type);            \
    4558              :       }
    4559              : #include "internal-fn.def"
    4560              : 
    4561              :     case IFN_LAST:
    4562              :       break;
    4563              :     }
    4564            0 :   gcc_unreachable ();
    4565              : }
    4566              : 
    4567              : /* Return true if FN is supported for type TYPE when the optimization
    4568              :    type is OPT_TYPE.  The caller knows that the "type0" and "type1"
    4569              :    fields of FN's direct_internal_fn_info structure are the same.  */
    4570              : 
    4571              : bool
    4572      4252845 : direct_internal_fn_supported_p (internal_fn fn, tree type,
    4573              :                                 optimization_type opt_type)
    4574              : {
    4575      4252845 :   const direct_internal_fn_info &info = direct_internal_fn (fn);
    4576      4252845 :   gcc_checking_assert (info.type0 == info.type1);
    4577      4252845 :   return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
    4578              : }
    4579              : 
    4580              : /* Return true if the STMT is supported when the optimization type is OPT_TYPE,
    4581              :    given that STMT is a call to a direct internal function.  */
    4582              : 
    4583              : bool
    4584          389 : direct_internal_fn_supported_p (gcall *stmt, optimization_type opt_type)
    4585              : {
    4586          389 :   internal_fn fn = gimple_call_internal_fn (stmt);
    4587          389 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4588          389 :   return direct_internal_fn_supported_p (fn, types, opt_type);
    4589              : }
    4590              : 
    4591              : /* Return true if FN is a binary operation and if FN is commutative.  */
    4592              : 
    4593              : bool
    4594     34763901 : commutative_binary_fn_p (internal_fn fn)
    4595              : {
    4596     34763901 :   switch (fn)
    4597              :     {
    4598              :     case IFN_AVG_FLOOR:
    4599              :     case IFN_AVG_CEIL:
    4600              :     case IFN_MULH:
    4601              :     case IFN_MULHS:
    4602              :     case IFN_MULHRS:
    4603              :     case IFN_FMIN:
    4604              :     case IFN_FMAX:
    4605              :     case IFN_COMPLEX_MUL:
    4606              :     case IFN_UBSAN_CHECK_ADD:
    4607              :     case IFN_UBSAN_CHECK_MUL:
    4608              :     case IFN_ADD_OVERFLOW:
    4609              :     case IFN_MUL_OVERFLOW:
    4610              :     case IFN_SAT_ADD:
    4611              :     case IFN_SAT_MUL:
    4612              :     case IFN_VEC_WIDEN_PLUS:
    4613              :     case IFN_VEC_WIDEN_PLUS_LO:
    4614              :     case IFN_VEC_WIDEN_PLUS_HI:
    4615              :     case IFN_VEC_WIDEN_PLUS_EVEN:
    4616              :     case IFN_VEC_WIDEN_PLUS_ODD:
    4617              :       return true;
    4618              : 
    4619     33854273 :     default:
    4620     33854273 :       return false;
    4621              :     }
    4622              : }
    4623              : 
    4624              : /* Return true if FN is a ternary operation and if its first two arguments
    4625              :    are commutative.  */
    4626              : 
    4627              : bool
    4628     28383881 : commutative_ternary_fn_p (internal_fn fn)
    4629              : {
    4630     28383881 :   switch (fn)
    4631              :     {
    4632              :     case IFN_FMA:
    4633              :     case IFN_FMS:
    4634              :     case IFN_FNMA:
    4635              :     case IFN_FNMS:
    4636              :     case IFN_UADDC:
    4637              :       return true;
    4638              : 
    4639     28251861 :     default:
    4640     28251861 :       return false;
    4641              :     }
    4642              : }
    4643              : 
    4644              : /* Return true if FN is an associative binary operation.  */
    4645              : 
    4646              : bool
    4647           52 : associative_binary_fn_p (internal_fn fn)
    4648              : {
    4649           52 :   switch (fn)
    4650              :     {
    4651              :     case IFN_FMIN:
    4652              :     case IFN_FMAX:
    4653              :       return true;
    4654              : 
    4655            0 :     default:
    4656            0 :       return false;
    4657              :     }
    4658              : }
    4659              : 
    4660              : /* If FN is commutative in two consecutive arguments, return the
    4661              :    index of the first, otherwise return -1.  */
    4662              : 
    4663              : int
    4664     28718267 : first_commutative_argument (internal_fn fn)
    4665              : {
    4666     28718267 :   switch (fn)
    4667              :     {
    4668              :     case IFN_COND_ADD:
    4669              :     case IFN_COND_MUL:
    4670              :     case IFN_COND_MIN:
    4671              :     case IFN_COND_MAX:
    4672              :     case IFN_COND_FMIN:
    4673              :     case IFN_COND_FMAX:
    4674              :     case IFN_COND_AND:
    4675              :     case IFN_COND_IOR:
    4676              :     case IFN_COND_XOR:
    4677              :     case IFN_COND_FMA:
    4678              :     case IFN_COND_FMS:
    4679              :     case IFN_COND_FNMA:
    4680              :     case IFN_COND_FNMS:
    4681              :     case IFN_COND_LEN_ADD:
    4682              :     case IFN_COND_LEN_MUL:
    4683              :     case IFN_COND_LEN_MIN:
    4684              :     case IFN_COND_LEN_MAX:
    4685              :     case IFN_COND_LEN_FMIN:
    4686              :     case IFN_COND_LEN_FMAX:
    4687              :     case IFN_COND_LEN_AND:
    4688              :     case IFN_COND_LEN_IOR:
    4689              :     case IFN_COND_LEN_XOR:
    4690              :     case IFN_COND_LEN_FMA:
    4691              :     case IFN_COND_LEN_FMS:
    4692              :     case IFN_COND_LEN_FNMA:
    4693              :     case IFN_COND_LEN_FNMS:
    4694              :       return 1;
    4695              : 
    4696     28694648 :     default:
    4697     28694648 :       if (commutative_binary_fn_p (fn)
    4698     28694648 :           || commutative_ternary_fn_p (fn))
    4699       447545 :         return 0;
    4700              :       return -1;
    4701              :     }
    4702              : }
    4703              : 
    4704              : /* Return true if this CODE describes an internal_fn that returns a vector with
    4705              :    elements twice as wide as the element size of the input vectors.  */
    4706              : 
    4707              : bool
    4708      2110764 : widening_fn_p (code_helper code)
    4709              : {
    4710      2110764 :   if (!code.is_fn_code ())
    4711              :     return false;
    4712              : 
    4713       219538 :   if (!internal_fn_p ((combined_fn) code))
    4714              :     return false;
    4715              : 
    4716       219538 :   internal_fn fn = as_internal_fn ((combined_fn) code);
    4717       219538 :   switch (fn)
    4718              :     {
    4719              :     #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
    4720              :     case IFN_##NAME:                                              \
    4721              :     case IFN_##NAME##_HI:                                         \
    4722              :     case IFN_##NAME##_LO:                                         \
    4723              :     case IFN_##NAME##_EVEN:                                       \
    4724              :     case IFN_##NAME##_ODD:                                        \
    4725              :       return true;
    4726              :     #include "internal-fn.def"
    4727              : 
    4728              :     default:
    4729              :       return false;
    4730              :     }
    4731              : }
    4732              : 
    4733              : /* Return true if this CODE describes an internal_fn that returns a vector with
    4734              :    elements twice as wide as the element size of the input vectors and operates
    4735              :    on even/odd parts of the input.  */
    4736              : 
    4737              : bool
    4738        20988 : widening_evenodd_fn_p (code_helper code)
    4739              : {
    4740        20988 :   if (!code.is_fn_code ())
    4741              :     return false;
    4742              : 
    4743            0 :   if (!internal_fn_p ((combined_fn) code))
    4744              :     return false;
    4745              : 
    4746            0 :   internal_fn fn = as_internal_fn ((combined_fn) code);
    4747            0 :   switch (fn)
    4748              :     {
    4749              :     #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
    4750              :     case IFN_##NAME##_EVEN:                                       \
    4751              :     case IFN_##NAME##_ODD:                                        \
    4752              :       return true;
    4753              :     #include "internal-fn.def"
    4754              : 
    4755              :     default:
    4756              :       return false;
    4757              :     }
    4758              : }
    4759              : 
    4760              : /* Return true if IFN_SET_EDOM is supported.  */
    4761              : 
    4762              : bool
    4763          140 : set_edom_supported_p (void)
    4764              : {
    4765              : #ifdef TARGET_EDOM
    4766              :   return true;
    4767              : #else
    4768          140 :   return false;
    4769              : #endif
    4770              : }
    4771              : 
    4772              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4773              :   static void                                           \
    4774              :   expand_##CODE (internal_fn fn, gcall *stmt)           \
    4775              :   {                                                     \
    4776              :     expand_##TYPE##_optab_fn (fn, stmt, OPTAB##_optab); \
    4777              :   }
    4778              : #define DEF_INTERNAL_INT_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
    4779              : #define DEF_INTERNAL_INTSZ_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
    4780              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
    4781              :                                      UNSIGNED_OPTAB, TYPE)              \
    4782              :   static void                                                           \
    4783              :   expand_##CODE (internal_fn fn, gcall *stmt)                           \
    4784              :   {                                                                     \
    4785              :     tree_pair types = direct_internal_fn_types (fn, stmt);              \
    4786              :     optab which_optab = direct_internal_fn_optab (fn, types);           \
    4787              :     expand_##TYPE##_optab_fn (fn, stmt, which_optab);                   \
    4788              :   }
    4789              : #include "internal-fn.def"
    4790              : 
    4791              : /* Routines to expand each internal function, indexed by function number.
    4792              :    Each routine has the prototype:
    4793              : 
    4794              :        expand_<NAME> (gcall *stmt)
    4795              : 
    4796              :    where STMT is the statement that performs the call. */
    4797              : static void (*const internal_fn_expanders[]) (internal_fn, gcall *) = {
    4798              : 
    4799              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) expand_##CODE,
    4800              : #include "internal-fn.def"
    4801              :   0
    4802              : };
    4803              : 
    4804              : /* Invoke T(CODE, SUFFIX) for each conditional function IFN_COND_##SUFFIX
    4805              :    that maps to a tree code CODE.  There is also an IFN_COND_LEN_##SUFFIX
    4806              :    for each such IFN_COND_##SUFFIX.  */
    4807              : #define FOR_EACH_CODE_MAPPING(T) \
    4808              :   T (PLUS_EXPR, ADD) \
    4809              :   T (MINUS_EXPR, SUB) \
    4810              :   T (MULT_EXPR, MUL) \
    4811              :   T (TRUNC_DIV_EXPR, DIV) \
    4812              :   T (TRUNC_MOD_EXPR, MOD) \
    4813              :   T (RDIV_EXPR, RDIV) \
    4814              :   T (MIN_EXPR, MIN) \
    4815              :   T (MAX_EXPR, MAX) \
    4816              :   T (BIT_AND_EXPR, AND) \
    4817              :   T (BIT_IOR_EXPR, IOR) \
    4818              :   T (BIT_XOR_EXPR, XOR) \
    4819              :   T (LSHIFT_EXPR, SHL) \
    4820              :   T (RSHIFT_EXPR, SHR) \
    4821              :   T (NEGATE_EXPR, NEG)
    4822              : 
    4823              : /* Return a function that only performs CODE when a certain condition is met
    4824              :    and that uses a given fallback value otherwise.  For example, if CODE is
    4825              :    a binary operation associated with conditional function FN:
    4826              : 
    4827              :      LHS = FN (COND, A, B, ELSE)
    4828              : 
    4829              :    is equivalent to the C expression:
    4830              : 
    4831              :      LHS = COND ? A CODE B : ELSE;
    4832              : 
    4833              :    operating elementwise if the operands are vectors.
    4834              : 
    4835              :    Return IFN_LAST if no such function exists.  */
    4836              : 
    4837              : internal_fn
    4838       573538 : get_conditional_internal_fn (tree_code code)
    4839              : {
    4840       573538 :   switch (code)
    4841              :     {
    4842              : #define CASE(CODE, IFN) case CODE: return IFN_COND_##IFN;
    4843              :       FOR_EACH_CODE_MAPPING(CASE)
    4844              : #undef CASE
    4845              :     default:
    4846              :       return IFN_LAST;
    4847              :     }
    4848              : }
    4849              : 
    4850              : /* If IFN implements the conditional form of a tree code, return that
    4851              :    tree code, otherwise return ERROR_MARK.  */
    4852              : 
    4853              : tree_code
    4854      3486989 : conditional_internal_fn_code (internal_fn ifn)
    4855              : {
    4856      3486989 :   switch (ifn)
    4857              :     {
    4858              : #define CASE(CODE, IFN)                                                        \
    4859              :   case IFN_COND_##IFN:                                                         \
    4860              :   case IFN_COND_LEN_##IFN:                                                     \
    4861              :     return CODE;
    4862              :       FOR_EACH_CODE_MAPPING (CASE)
    4863              : #undef CASE
    4864              :       default:
    4865              :         return ERROR_MARK;
    4866              :     }
    4867              : }
    4868              : 
    4869              : /* Like get_conditional_internal_fn, but return a function that
    4870              :    additionally restricts the operation to the leading elements
    4871              :    of a vector.  The number of elements to process is given by a length
    4872              :    and bias pair, as for IFN_LOAD_LEN.  The values of the remaining
    4873              :    elements are taken from the fallback ("else") argument.
    4874              : 
    4875              :    For example, if CODE is a binary operation associated with FN:
    4876              : 
    4877              :      LHS = FN (COND, A, B, ELSE, LEN, BIAS)
    4878              : 
    4879              :    is equivalent to the C code:
    4880              : 
    4881              :      for (int i = 0; i < NUNITS; i++)
    4882              :       {
    4883              :         if (i < LEN + BIAS && COND[i])
    4884              :           LHS[i] = A[i] CODE B[i];
    4885              :         else
    4886              :           LHS[i] = ELSE[i];
    4887              :       }
    4888              : */
    4889              : 
    4890              : internal_fn
    4891       550107 : get_conditional_len_internal_fn (tree_code code)
    4892              : {
    4893       550107 :   switch (code)
    4894              :     {
    4895              : #define CASE(CODE, IFN) case CODE: return IFN_COND_LEN_##IFN;
    4896              :       FOR_EACH_CODE_MAPPING(CASE)
    4897              : #undef CASE
    4898              :     default:
    4899              :       return IFN_LAST;
    4900              :     }
    4901              : }
    4902              : 
    4903              : /* Invoke T(IFN) for each internal function IFN that also has an
    4904              :    IFN_COND_* form.  */
    4905              : #define FOR_EACH_COND_FN_PAIR(T) \
    4906              :   T (FMAX) \
    4907              :   T (FMIN) \
    4908              :   T (FMA) \
    4909              :   T (FMS) \
    4910              :   T (FNMA) \
    4911              :   T (FNMS) \
    4912              :   T (SQRT) \
    4913              :   T (ROUND) \
    4914              :   T (FLOOR) \
    4915              :   T (RINT) \
    4916              :   T (CEIL)
    4917              : 
    4918              : /* Return a function that only performs internal function FN when a
    4919              :    certain condition is met and that uses a given fallback value otherwise.
    4920              :    In other words, the returned function FN' is such that:
    4921              : 
    4922              :      LHS = FN' (COND, A1, ... An, ELSE)
    4923              : 
    4924              :    is equivalent to the C expression:
    4925              : 
    4926              :      LHS = COND ? FN (A1, ..., An) : ELSE;
    4927              : 
    4928              :    operating elementwise if the operands are vectors.
    4929              : 
    4930              :    Return IFN_LAST if no such function exists.  */
    4931              : 
    4932              : internal_fn
    4933        10190 : get_conditional_internal_fn (internal_fn fn)
    4934              : {
    4935        10190 :   switch (fn)
    4936              :     {
    4937              : #define CASE(NAME) case IFN_##NAME: return IFN_COND_##NAME;
    4938         2160 :       FOR_EACH_COND_FN_PAIR(CASE)
    4939              : #undef CASE
    4940         8029 :     default:
    4941         8029 :       return IFN_LAST;
    4942              :     }
    4943              : }
    4944              : 
    4945              : /* If there exists an internal function like IFN that operates on vectors,
    4946              :    but with additional length and bias parameters, return the internal_fn
    4947              :    for that function, otherwise return IFN_LAST.  */
    4948              : internal_fn
    4949        12315 : get_len_internal_fn (internal_fn fn)
    4950              : {
    4951        12315 :   switch (fn)
    4952              :     {
    4953              : #define DEF_INTERNAL_COND_FN(NAME, ...)                                        \
    4954              :   case IFN_COND_##NAME:                                                        \
    4955              :     return IFN_COND_LEN_##NAME;
    4956              : #define DEF_INTERNAL_SIGNED_COND_FN(NAME, ...)                                 \
    4957              :   case IFN_COND_##NAME:                                                        \
    4958              :     return IFN_COND_LEN_##NAME;
    4959              : #include "internal-fn.def"
    4960         7991 :     default:
    4961         7991 :       break;
    4962              :     }
    4963              : 
    4964         7991 :   switch (fn)
    4965              :     {
    4966              :     case IFN_MASK_LOAD:
    4967              :       return IFN_MASK_LEN_LOAD;
    4968              :     case IFN_MASK_LOAD_LANES:
    4969              :       return IFN_MASK_LEN_LOAD_LANES;
    4970              :     case IFN_MASK_GATHER_LOAD:
    4971              :       return IFN_MASK_LEN_GATHER_LOAD;
    4972              :     default:
    4973              :       return IFN_LAST;
    4974              :     }
    4975              : }
    4976              : 
    4977              : /* If IFN implements the conditional form of an unconditional internal
    4978              :    function, return that unconditional function, otherwise return IFN_LAST.  */
    4979              : 
    4980              : internal_fn
    4981      3432952 : get_unconditional_internal_fn (internal_fn ifn)
    4982              : {
    4983      3432952 :   switch (ifn)
    4984              :     {
    4985              : #define CASE(NAME)                                                             \
    4986              :     case IFN_COND_##NAME:                                                      \
    4987              :     case IFN_COND_LEN_##NAME:                                                  \
    4988              :       return IFN_##NAME;
    4989              : FOR_EACH_COND_FN_PAIR (CASE)
    4990              : #undef CASE
    4991              :     default:
    4992              :       return IFN_LAST;
    4993              :     }
    4994              : }
    4995              : 
    4996              : /* Return true if STMT can be interpreted as a conditional tree code
    4997              :    operation of the form:
    4998              : 
    4999              :      LHS = COND ? OP (RHS1, ...) : ELSE;
    5000              : 
    5001              :    operating elementwise if the operands are vectors.  This includes
    5002              :    the case of an all-true COND, so that the operation always happens.
    5003              : 
    5004              :    There is an alternative approach to interpret the STMT when the operands
    5005              :    are vectors which is the operation predicated by both conditional mask
    5006              :    and loop control length, the equivalent C code:
    5007              : 
    5008              :      for (int i = 0; i < NUNTIS; i++)
    5009              :       {
    5010              :         if (i < LEN + BIAS && COND[i])
    5011              :           LHS[i] = A[i] CODE B[i];
    5012              :         else
    5013              :           LHS[i] = ELSE[i];
    5014              :       }
    5015              : 
    5016              :    When returning true, set:
    5017              : 
    5018              :    - *COND_OUT to the condition COND, or to NULL_TREE if the condition
    5019              :      is known to be all-true
    5020              :    - *CODE_OUT to the tree code
    5021              :    - OPS[I] to operand I of *CODE_OUT
    5022              :    - *ELSE_OUT to the fallback value ELSE, or to NULL_TREE if the
    5023              :      condition is known to be all true.
    5024              :    - *LEN to the len argument if it COND_LEN_* operations or to NULL_TREE.
    5025              :    - *BIAS to the bias argument if it COND_LEN_* operations or to NULL_TREE.  */
    5026              : 
    5027              : bool
    5028        40335 : can_interpret_as_conditional_op_p (gimple *stmt, tree *cond_out,
    5029              :                                    tree_code *code_out,
    5030              :                                    tree (&ops)[3], tree *else_out,
    5031              :                                    tree *len, tree *bias)
    5032              : {
    5033        40335 :   *len = NULL_TREE;
    5034        40335 :   *bias = NULL_TREE;
    5035        40335 :   if (gassign *assign = dyn_cast <gassign *> (stmt))
    5036              :     {
    5037        37760 :       *cond_out = NULL_TREE;
    5038        37760 :       *code_out = gimple_assign_rhs_code (assign);
    5039        37760 :       ops[0] = gimple_assign_rhs1 (assign);
    5040        37760 :       ops[1] = gimple_assign_rhs2 (assign);
    5041        37760 :       ops[2] = gimple_assign_rhs3 (assign);
    5042        37760 :       *else_out = NULL_TREE;
    5043        37760 :       return true;
    5044              :     }
    5045         2575 :   if (gcall *call = dyn_cast <gcall *> (stmt))
    5046         1998 :     if (gimple_call_internal_p (call))
    5047              :       {
    5048         1941 :         internal_fn ifn = gimple_call_internal_fn (call);
    5049         1941 :         tree_code code = conditional_internal_fn_code (ifn);
    5050         1941 :         int len_index = internal_fn_len_index (ifn);
    5051         1941 :         int cond_nargs = len_index >= 0 ? 4 : 2;
    5052         1941 :         if (code != ERROR_MARK)
    5053              :           {
    5054          216 :             *cond_out = gimple_call_arg (call, 0);
    5055          216 :             *code_out = code;
    5056          216 :             unsigned int nops = gimple_call_num_args (call) - cond_nargs;
    5057          864 :             for (unsigned int i = 0; i < 3; ++i)
    5058          648 :               ops[i] = i < nops ? gimple_call_arg (call, i + 1) : NULL_TREE;
    5059          216 :             *else_out = gimple_call_arg (call, nops + 1);
    5060          216 :             if (len_index < 0)
    5061              :               {
    5062          216 :                 if (integer_truep (*cond_out))
    5063              :                   {
    5064            0 :                     *cond_out = NULL_TREE;
    5065            0 :                     *else_out = NULL_TREE;
    5066              :                   }
    5067              :               }
    5068              :             else
    5069              :               {
    5070            0 :                 *len = gimple_call_arg (call, len_index);
    5071            0 :                 *bias = gimple_call_arg (call, len_index + 1);
    5072              :               }
    5073              :             return true;
    5074              :           }
    5075              :       }
    5076              :   return false;
    5077              : }
    5078              : 
    5079              : /* Return true if IFN is some form of load from memory.  */
    5080              : 
    5081              : bool
    5082       992379 : internal_load_fn_p (internal_fn fn)
    5083              : {
    5084       992379 :   switch (fn)
    5085              :     {
    5086              :     case IFN_MASK_LOAD:
    5087              :     case IFN_LOAD_LANES:
    5088              :     case IFN_MASK_LOAD_LANES:
    5089              :     case IFN_MASK_LEN_LOAD_LANES:
    5090              :     case IFN_GATHER_LOAD:
    5091              :     case IFN_MASK_GATHER_LOAD:
    5092              :     case IFN_MASK_LEN_GATHER_LOAD:
    5093              :     case IFN_LEN_LOAD:
    5094              :     case IFN_MASK_LEN_LOAD:
    5095              :       return true;
    5096              : 
    5097       259801 :     default:
    5098       259801 :       return false;
    5099              :     }
    5100              : }
    5101              : 
    5102              : /* Return true if IFN is some form of store to memory.  */
    5103              : 
    5104              : bool
    5105       559463 : internal_store_fn_p (internal_fn fn)
    5106              : {
    5107       559463 :   switch (fn)
    5108              :     {
    5109              :     case IFN_MASK_STORE:
    5110              :     case IFN_STORE_LANES:
    5111              :     case IFN_MASK_STORE_LANES:
    5112              :     case IFN_MASK_LEN_STORE_LANES:
    5113              :     case IFN_SCATTER_STORE:
    5114              :     case IFN_MASK_SCATTER_STORE:
    5115              :     case IFN_MASK_LEN_SCATTER_STORE:
    5116              :     case IFN_LEN_STORE:
    5117              :     case IFN_MASK_LEN_STORE:
    5118              :       return true;
    5119              : 
    5120       546817 :     default:
    5121       546817 :       return false;
    5122              :     }
    5123              : }
    5124              : 
    5125              : /* Return true if IFN is some form of gather load or scatter store.  */
    5126              : 
    5127              : bool
    5128        49526 : internal_gather_scatter_fn_p (internal_fn fn)
    5129              : {
    5130        49526 :   switch (fn)
    5131              :     {
    5132              :     case IFN_GATHER_LOAD:
    5133              :     case IFN_MASK_GATHER_LOAD:
    5134              :     case IFN_MASK_LEN_GATHER_LOAD:
    5135              :     case IFN_SCATTER_STORE:
    5136              :     case IFN_MASK_SCATTER_STORE:
    5137              :     case IFN_MASK_LEN_SCATTER_STORE:
    5138              :       return true;
    5139              : 
    5140        49526 :     default:
    5141        49526 :       return false;
    5142              :     }
    5143              : }
    5144              : 
    5145              : /* If FN takes a vector len argument, return the index of that argument,
    5146              :    otherwise return -1.  */
    5147              : 
    5148              : int
    5149      3318770 : internal_fn_len_index (internal_fn fn)
    5150              : {
    5151      3318770 :   switch (fn)
    5152              :     {
    5153              :     case IFN_LEN_LOAD:
    5154              :       return 3;
    5155              :     case IFN_LEN_STORE:
    5156              :       return 2;
    5157              : 
    5158              :     case IFN_MASK_LEN_SCATTER_STORE:
    5159              :       return 6;
    5160              : 
    5161              :     case IFN_MASK_LEN_STRIDED_LOAD:
    5162              :       return 5;
    5163              : 
    5164              :     case IFN_MASK_LEN_GATHER_LOAD:
    5165              :       return 7;
    5166              : 
    5167              :     case IFN_COND_LEN_FMA:
    5168              :     case IFN_COND_LEN_FMS:
    5169              :     case IFN_COND_LEN_FNMA:
    5170              :     case IFN_COND_LEN_FNMS:
    5171              :       return 5;
    5172              : 
    5173              :     case IFN_COND_LEN_ADD:
    5174              :     case IFN_COND_LEN_SUB:
    5175              :     case IFN_COND_LEN_MUL:
    5176              :     case IFN_COND_LEN_DIV:
    5177              :     case IFN_COND_LEN_MOD:
    5178              :     case IFN_COND_LEN_RDIV:
    5179              :     case IFN_COND_LEN_MIN:
    5180              :     case IFN_COND_LEN_MAX:
    5181              :     case IFN_COND_LEN_FMIN:
    5182              :     case IFN_COND_LEN_FMAX:
    5183              :     case IFN_COND_LEN_AND:
    5184              :     case IFN_COND_LEN_IOR:
    5185              :     case IFN_COND_LEN_XOR:
    5186              :     case IFN_COND_LEN_SHL:
    5187              :     case IFN_COND_LEN_SHR:
    5188              :     case IFN_MASK_LEN_STRIDED_STORE:
    5189              :       return 4;
    5190              : 
    5191              :     case IFN_COND_LEN_NEG:
    5192              :     case IFN_MASK_LEN_STORE:
    5193              :     case IFN_MASK_LEN_STORE_LANES:
    5194              :     case IFN_VCOND_MASK_LEN:
    5195              :       return 3;
    5196              : 
    5197              :     case IFN_MASK_LEN_LOAD:
    5198              :     case IFN_MASK_LEN_LOAD_LANES:
    5199              :       return 4;
    5200              : 
    5201              :     default:
    5202              :       return -1;
    5203              :     }
    5204              : }
    5205              : 
    5206              : /* If FN is an IFN_COND_* or IFN_COND_LEN_* function, return the index of the
    5207              :    argument that is used when the condition is false.  Return -1 otherwise.  */
    5208              : 
    5209              : int
    5210        84686 : internal_fn_else_index (internal_fn fn)
    5211              : {
    5212        84686 :   switch (fn)
    5213              :     {
    5214              :     case IFN_COND_NEG:
    5215              :     case IFN_COND_NOT:
    5216              :     case IFN_COND_SQRT:
    5217              :     case IFN_COND_CEIL:
    5218              :     case IFN_COND_FLOOR:
    5219              :     case IFN_COND_ROUND:
    5220              :     case IFN_COND_RINT:
    5221              :     case IFN_COND_LEN_NEG:
    5222              :     case IFN_COND_LEN_NOT:
    5223              :     case IFN_COND_LEN_SQRT:
    5224              :     case IFN_COND_LEN_CEIL:
    5225              :     case IFN_COND_LEN_FLOOR:
    5226              :     case IFN_COND_LEN_ROUND:
    5227              :     case IFN_COND_LEN_RINT:
    5228              :       return 2;
    5229              : 
    5230              :     case IFN_LEN_LOAD:
    5231              :       return 2;
    5232              : 
    5233              :     case IFN_COND_ADD:
    5234              :     case IFN_COND_SUB:
    5235              :     case IFN_COND_MUL:
    5236              :     case IFN_COND_DIV:
    5237              :     case IFN_COND_MOD:
    5238              :     case IFN_COND_MIN:
    5239              :     case IFN_COND_MAX:
    5240              :     case IFN_COND_FMIN:
    5241              :     case IFN_COND_FMAX:
    5242              :     case IFN_COND_AND:
    5243              :     case IFN_COND_IOR:
    5244              :     case IFN_COND_XOR:
    5245              :     case IFN_COND_SHL:
    5246              :     case IFN_COND_SHR:
    5247              :     case IFN_COND_LEN_ADD:
    5248              :     case IFN_COND_LEN_SUB:
    5249              :     case IFN_COND_LEN_MUL:
    5250              :     case IFN_COND_LEN_DIV:
    5251              :     case IFN_COND_LEN_MOD:
    5252              :     case IFN_COND_LEN_MIN:
    5253              :     case IFN_COND_LEN_MAX:
    5254              :     case IFN_COND_LEN_FMIN:
    5255              :     case IFN_COND_LEN_FMAX:
    5256              :     case IFN_COND_LEN_AND:
    5257              :     case IFN_COND_LEN_IOR:
    5258              :     case IFN_COND_LEN_XOR:
    5259              :     case IFN_COND_LEN_SHL:
    5260              :     case IFN_COND_LEN_SHR:
    5261              :       return 3;
    5262              : 
    5263              :     case IFN_MASK_LOAD:
    5264              :     case IFN_MASK_LEN_LOAD:
    5265              :     case IFN_MASK_LOAD_LANES:
    5266              :     case IFN_MASK_LEN_LOAD_LANES:
    5267              :       return 3;
    5268              : 
    5269              :     case IFN_COND_FMA:
    5270              :     case IFN_COND_FMS:
    5271              :     case IFN_COND_FNMA:
    5272              :     case IFN_COND_FNMS:
    5273              :     case IFN_COND_LEN_FMA:
    5274              :     case IFN_COND_LEN_FMS:
    5275              :     case IFN_COND_LEN_FNMA:
    5276              :     case IFN_COND_LEN_FNMS:
    5277              :     case IFN_MASK_LEN_STRIDED_LOAD:
    5278              :       return 4;
    5279              : 
    5280              :     case IFN_MASK_GATHER_LOAD:
    5281              :     case IFN_MASK_LEN_GATHER_LOAD:
    5282              :       return 6;
    5283              : 
    5284              :     default:
    5285              :       return -1;
    5286              :     }
    5287              : 
    5288              :   return -1;
    5289              : }
    5290              : 
    5291              : /* If FN takes a vector mask argument, return the index of that argument,
    5292              :    otherwise return -1.  */
    5293              : 
    5294              : int
    5295       208853 : internal_fn_mask_index (internal_fn fn)
    5296              : {
    5297       208853 :   switch (fn)
    5298              :     {
    5299              :     case IFN_MASK_LOAD:
    5300              :     case IFN_MASK_LOAD_LANES:
    5301              :     case IFN_MASK_LEN_LOAD_LANES:
    5302              :     case IFN_MASK_STORE:
    5303              :     case IFN_MASK_STORE_LANES:
    5304              :     case IFN_MASK_LEN_STORE_LANES:
    5305              :     case IFN_MASK_LEN_LOAD:
    5306              :     case IFN_MASK_LEN_STORE:
    5307              :       return 2;
    5308              : 
    5309            0 :     case IFN_MASK_LEN_STRIDED_LOAD:
    5310            0 :     case IFN_MASK_LEN_STRIDED_STORE:
    5311            0 :       return 3;
    5312              : 
    5313            0 :     case IFN_MASK_GATHER_LOAD:
    5314            0 :     case IFN_MASK_SCATTER_STORE:
    5315            0 :     case IFN_MASK_LEN_GATHER_LOAD:
    5316            0 :     case IFN_MASK_LEN_SCATTER_STORE:
    5317            0 :       return 5;
    5318              : 
    5319              :     case IFN_VCOND_MASK:
    5320              :     case IFN_VCOND_MASK_LEN:
    5321              :       return 0;
    5322              : 
    5323       164954 :     default:
    5324       164954 :       return (conditional_internal_fn_code (fn) != ERROR_MARK
    5325       164954 :               || get_unconditional_internal_fn (fn) != IFN_LAST ? 0 : -1);
    5326              :     }
    5327              : }
    5328              : 
    5329              : /* If FN takes a value that should be stored to memory, return the index
    5330              :    of that argument, otherwise return -1.  */
    5331              : 
    5332              : int
    5333        26053 : internal_fn_stored_value_index (internal_fn fn)
    5334              : {
    5335        26053 :   switch (fn)
    5336              :     {
    5337              :     case IFN_MASK_LEN_STRIDED_STORE:
    5338              :       return 2;
    5339              : 
    5340              :     case IFN_MASK_STORE:
    5341              :     case IFN_MASK_STORE_LANES:
    5342              :       return 3;
    5343              :     case IFN_SCATTER_STORE:
    5344              :     case IFN_MASK_SCATTER_STORE:
    5345              :     case IFN_MASK_LEN_SCATTER_STORE:
    5346              :       return 4;
    5347              : 
    5348              :     case IFN_LEN_STORE:
    5349              :       return 4;
    5350              : 
    5351              :     case IFN_MASK_LEN_STORE:
    5352              :     case IFN_MASK_LEN_STORE_LANES:
    5353              :       return 5;
    5354              : 
    5355              :     default:
    5356              :       return -1;
    5357              :     }
    5358              : }
    5359              : 
    5360              : /* If FN has an alias pointer return its index, otherwise return -1.  */
    5361              : 
    5362              : int
    5363            0 : internal_fn_alias_ptr_index (internal_fn fn)
    5364              : {
    5365            0 :   switch (fn)
    5366              :     {
    5367              :     case IFN_MASK_LOAD:
    5368              :     case IFN_MASK_LEN_LOAD:
    5369              :     case IFN_GATHER_LOAD:
    5370              :     case IFN_MASK_GATHER_LOAD:
    5371              :     case IFN_MASK_LEN_GATHER_LOAD:
    5372              :     case IFN_SCATTER_STORE:
    5373              :     case IFN_MASK_SCATTER_STORE:
    5374              :     case IFN_MASK_LEN_SCATTER_STORE:
    5375              :       return 1;
    5376              : 
    5377            0 :     default:
    5378            0 :       return -1;
    5379              :     }
    5380              : }
    5381              : 
    5382              : /* If FN is a gather/scatter return the index of its offset argument,
    5383              :    otherwise return -1.  */
    5384              : 
    5385              : int
    5386            0 : internal_fn_offset_index (internal_fn fn)
    5387              : {
    5388            0 :   if (!internal_gather_scatter_fn_p (fn))
    5389              :     return -1;
    5390              : 
    5391            0 :   switch (fn)
    5392              :     {
    5393              :     case IFN_GATHER_LOAD:
    5394              :     case IFN_MASK_GATHER_LOAD:
    5395              :     case IFN_MASK_LEN_GATHER_LOAD:
    5396              :     case IFN_SCATTER_STORE:
    5397              :     case IFN_MASK_SCATTER_STORE:
    5398              :     case IFN_MASK_LEN_SCATTER_STORE:
    5399              :       return 2;
    5400              : 
    5401              :     default:
    5402              :       return -1;
    5403              :     }
    5404              : }
    5405              : 
    5406              : /* If FN is a gather/scatter return the index of its scale argument,
    5407              :    otherwise return -1.  */
    5408              : 
    5409              : int
    5410            0 : internal_fn_scale_index (internal_fn fn)
    5411              : {
    5412            0 :   if (!internal_gather_scatter_fn_p (fn))
    5413              :     return -1;
    5414              : 
    5415            0 :   switch (fn)
    5416              :     {
    5417              :     case IFN_GATHER_LOAD:
    5418              :     case IFN_MASK_GATHER_LOAD:
    5419              :     case IFN_MASK_LEN_GATHER_LOAD:
    5420              :     case IFN_SCATTER_STORE:
    5421              :     case IFN_MASK_SCATTER_STORE:
    5422              :     case IFN_MASK_LEN_SCATTER_STORE:
    5423              :       return 3;
    5424              : 
    5425              :     default:
    5426              :       return -1;
    5427              :     }
    5428              : }
    5429              : 
    5430              : /* Store all supported else values for the optab referred to by ICODE
    5431              :    in ELSE_VALS.  The index of the else operand must be specified in
    5432              :    ELSE_INDEX.  */
    5433              : 
    5434              : void
    5435        62955 : get_supported_else_vals (enum insn_code icode, unsigned else_index,
    5436              :                          vec<int> &else_vals)
    5437              : {
    5438        62955 :   const struct insn_data_d *data = &insn_data[icode];
    5439        62955 :   if ((int) else_index >= data->n_operands || (int) else_index == -1)
    5440              :     return;
    5441              : 
    5442        62955 :   machine_mode else_mode = data->operand[else_index].mode;
    5443              : 
    5444        62955 :   else_vals.truncate (0);
    5445              : 
    5446              :   /* For now we only support else values of 0, -1, and "undefined".  */
    5447        62955 :   if (insn_operand_matches (icode, else_index, CONST0_RTX (else_mode)))
    5448        62955 :     else_vals.safe_push (MASK_LOAD_ELSE_ZERO);
    5449              : 
    5450        62955 :   if (insn_operand_matches (icode, else_index, gen_rtx_SCRATCH (else_mode)))
    5451            0 :     else_vals.safe_push (MASK_LOAD_ELSE_UNDEFINED);
    5452              : 
    5453        62955 :   if (GET_MODE_CLASS (else_mode) == MODE_VECTOR_INT
    5454        62955 :       && insn_operand_matches (icode, else_index, CONSTM1_RTX (else_mode)))
    5455            0 :     else_vals.safe_push (MASK_LOAD_ELSE_M1);
    5456              : }
    5457              : 
    5458              : /* Return true if the else value ELSE_VAL (one of MASK_LOAD_ELSE_ZERO,
    5459              :    MASK_LOAD_ELSE_M1, and MASK_LOAD_ELSE_UNDEFINED) is valid fo the optab
    5460              :    referred to by ICODE.  The index of the else operand must be specified
    5461              :    in ELSE_INDEX.  */
    5462              : 
    5463              : bool
    5464            0 : supported_else_val_p (enum insn_code icode, unsigned else_index, int else_val)
    5465              : {
    5466            0 :   if (else_val != MASK_LOAD_ELSE_ZERO && else_val != MASK_LOAD_ELSE_M1
    5467            0 :       && else_val != MASK_LOAD_ELSE_UNDEFINED)
    5468            0 :     gcc_unreachable ();
    5469              : 
    5470            0 :   auto_vec<int> else_vals;
    5471            0 :   get_supported_else_vals (icode, else_index, else_vals);
    5472            0 :   return else_vals.contains (else_val);
    5473            0 : }
    5474              : 
    5475              : /* Return true if the target supports gather load or scatter store function
    5476              :    IFN.  For loads, VECTOR_TYPE is the vector type of the load result,
    5477              :    while for stores it is the vector type of the stored data argument.
    5478              :    MEMORY_ELEMENT_TYPE is the type of the memory elements being loaded
    5479              :    or stored.  OFFSET_VECTOR_TYPE is the vector type that holds the
    5480              :    offset from the shared base address of each loaded or stored element.
    5481              :    SCALE is the amount by which these offsets should be multiplied
    5482              :    *after* they have been extended to address width.
    5483              :    If the target supports the gather load the supported else values
    5484              :    will be added to the vector ELSVAL points to if it is nonzero.  */
    5485              : 
    5486              : bool
    5487      3543198 : internal_gather_scatter_fn_supported_p (internal_fn ifn, tree vector_type,
    5488              :                                         tree memory_element_type,
    5489              :                                         tree offset_vector_type, int scale,
    5490              :                                         vec<int> *elsvals)
    5491              : {
    5492      3543198 :   if (!tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vector_type)),
    5493      3543198 :                            TYPE_SIZE (memory_element_type)))
    5494              :     return false;
    5495      3543198 :   if (maybe_ne (TYPE_VECTOR_SUBPARTS (vector_type),
    5496      7086396 :                 TYPE_VECTOR_SUBPARTS (offset_vector_type)))
    5497              :     return false;
    5498       968920 :   optab optab = direct_internal_fn_optab (ifn);
    5499       968920 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (vector_type),
    5500       968920 :                                            TYPE_MODE (offset_vector_type));
    5501       968920 :   int output_ops = internal_load_fn_p (ifn) ? 1 : 0;
    5502       968920 :   bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (offset_vector_type));
    5503       968920 :   bool ok = icode != CODE_FOR_nothing
    5504            0 :     && insn_operand_matches (icode, 2 + output_ops, GEN_INT (unsigned_p))
    5505       968920 :     && insn_operand_matches (icode, 3 + output_ops, GEN_INT (scale));
    5506              : 
    5507       968920 :   if (ok && elsvals)
    5508            0 :     get_supported_else_vals
    5509            0 :       (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
    5510              : 
    5511              :   return ok;
    5512              : }
    5513              : 
    5514              : /* Return true if the target supports a strided load/store function IFN
    5515              :    with VECTOR_TYPE.  If supported and ELSVALS is nonzero the supported else
    5516              :    values will be added to the vector ELSVALS points to.  */
    5517              : 
    5518              : bool
    5519         1868 : internal_strided_fn_supported_p (internal_fn ifn, tree vector_type,
    5520              :                                  vec<int> *elsvals)
    5521              : {
    5522         1868 :   machine_mode mode = TYPE_MODE (vector_type);
    5523         1868 :   optab optab = direct_internal_fn_optab (ifn);
    5524         1868 :   insn_code icode = direct_optab_handler (optab, mode);
    5525              : 
    5526         1868 :   bool ok = icode != CODE_FOR_nothing;
    5527              : 
    5528         1868 :   if (ok && elsvals)
    5529            0 :     get_supported_else_vals (icode, internal_fn_else_index (ifn), *elsvals);
    5530              : 
    5531         1868 :   return ok;
    5532              : }
    5533              : 
    5534              : /* Return true if the target supports IFN_CHECK_{RAW,WAR}_PTRS function IFN
    5535              :    for pointers of type TYPE when the accesses have LENGTH bytes and their
    5536              :    common byte alignment is ALIGN.  */
    5537              : 
    5538              : bool
    5539         5328 : internal_check_ptrs_fn_supported_p (internal_fn ifn, tree type,
    5540              :                                     poly_uint64 length, unsigned int align)
    5541              : {
    5542         5328 :   machine_mode mode = TYPE_MODE (type);
    5543         5328 :   optab optab = direct_internal_fn_optab (ifn);
    5544         5328 :   insn_code icode = direct_optab_handler (optab, mode);
    5545         5328 :   if (icode == CODE_FOR_nothing)
    5546              :     return false;
    5547            0 :   rtx length_rtx = immed_wide_int_const (length, mode);
    5548            0 :   return (insn_operand_matches (icode, 3, length_rtx)
    5549            0 :           && insn_operand_matches (icode, 4, GEN_INT (align)));
    5550              : }
    5551              : 
    5552              : /* Return the supported bias for IFN which is either IFN_{LEN_,MASK_LEN_,}LOAD
    5553              :    or IFN_{LEN_,MASK_LEN_,}STORE.  For now we only support the biases of 0 and
    5554              :    -1 (in case 0 is not an allowable length for {len_,mask_len_}load or
    5555              :    {len_,mask_len_}store). If none of the biases match what the backend
    5556              :    provides, return VECT_PARTIAL_BIAS_UNSUPPORTED.  */
    5557              : 
    5558              : signed char
    5559            0 : internal_len_load_store_bias (internal_fn ifn, machine_mode mode)
    5560              : {
    5561            0 :   optab optab = direct_internal_fn_optab (ifn);
    5562            0 :   insn_code icode = direct_optab_handler (optab, mode);
    5563            0 :   int bias_idx = internal_fn_len_index (ifn) + 1;
    5564              : 
    5565            0 :   if (icode == CODE_FOR_nothing)
    5566              :     {
    5567            0 :       machine_mode mask_mode;
    5568            0 :       if (!targetm.vectorize.get_mask_mode (mode).exists (&mask_mode))
    5569            0 :         return VECT_PARTIAL_BIAS_UNSUPPORTED;
    5570            0 :       if (ifn == IFN_LEN_LOAD)
    5571              :         {
    5572              :           /* Try MASK_LEN_LOAD.  */
    5573            0 :           optab = direct_internal_fn_optab (IFN_MASK_LEN_LOAD);
    5574            0 :           bias_idx = internal_fn_len_index (IFN_MASK_LEN_LOAD) + 1;
    5575              :         }
    5576              :       else
    5577              :         {
    5578              :           /* Try MASK_LEN_STORE.  */
    5579            0 :           optab = direct_internal_fn_optab (IFN_MASK_LEN_STORE);
    5580            0 :           bias_idx = internal_fn_len_index (IFN_MASK_LEN_STORE) + 1;
    5581              :         }
    5582            0 :       icode = convert_optab_handler (optab, mode, mask_mode);
    5583              :     }
    5584              : 
    5585            0 :   if (icode != CODE_FOR_nothing)
    5586              :     {
    5587              :       /* For now we only support biases of 0 or -1.  Try both of them.  */
    5588            0 :       if (insn_operand_matches (icode, bias_idx, GEN_INT (0)))
    5589              :         return 0;
    5590            0 :       if (insn_operand_matches (icode, bias_idx, GEN_INT (-1)))
    5591            0 :         return -1;
    5592              :     }
    5593              : 
    5594              :   return VECT_PARTIAL_BIAS_UNSUPPORTED;
    5595              : }
    5596              : 
    5597              : /* Expand STMT as though it were a call to internal function FN.  */
    5598              : 
    5599              : void
    5600       264938 : expand_internal_call (internal_fn fn, gcall *stmt)
    5601              : {
    5602       264938 :   internal_fn_expanders[fn] (fn, stmt);
    5603       264938 : }
    5604              : 
    5605              : /* Expand STMT, which is a call to internal function FN.  */
    5606              : 
    5607              : void
    5608       231512 : expand_internal_call (gcall *stmt)
    5609              : {
    5610       231512 :   expand_internal_call (gimple_call_internal_fn (stmt), stmt);
    5611       231512 : }
    5612              : 
    5613              : /* If TYPE is a vector type, return true if IFN is a direct internal
    5614              :    function that is supported for that type.  If TYPE is a scalar type,
    5615              :    return true if IFN is a direct internal function that is supported for
    5616              :    the target's preferred vector version of TYPE.  */
    5617              : 
    5618              : bool
    5619        17290 : vectorized_internal_fn_supported_p (internal_fn ifn, tree type)
    5620              : {
    5621        17290 :   if (VECTOR_MODE_P (TYPE_MODE (type)))
    5622        10981 :     return direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED);
    5623              : 
    5624         6309 :   scalar_mode smode;
    5625         6309 :   if (VECTOR_TYPE_P (type)
    5626         6309 :       || !is_a <scalar_mode> (TYPE_MODE (type), &smode))
    5627              :     return false;
    5628              : 
    5629         6298 :   machine_mode vmode = targetm.vectorize.preferred_simd_mode (smode);
    5630         6298 :   if (VECTOR_MODE_P (vmode))
    5631              :     {
    5632         6261 :       tree vectype = build_vector_type_for_mode (type, vmode);
    5633         6261 :       if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
    5634              :         return true;
    5635              :     }
    5636              : 
    5637         4283 :   auto_vector_modes vector_modes;
    5638         4283 :   targetm.vectorize.autovectorize_vector_modes (&vector_modes, true);
    5639        26710 :   for (machine_mode base_mode : vector_modes)
    5640        13861 :     if (related_vector_mode (base_mode, smode).exists (&vmode))
    5641              :       {
    5642        12162 :         tree vectype = build_vector_type_for_mode (type, vmode);
    5643        12162 :         if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
    5644              :           return true;
    5645              :       }
    5646              : 
    5647              :   return false;
    5648         4283 : }
    5649              : 
    5650              : void
    5651            0 : expand_SHUFFLEVECTOR (internal_fn, gcall *)
    5652              : {
    5653            0 :   gcc_unreachable ();
    5654              : }
    5655              : 
    5656              : void
    5657            0 : expand_PHI (internal_fn, gcall *)
    5658              : {
    5659            0 :   gcc_unreachable ();
    5660              : }
    5661              : 
    5662              : void
    5663          333 : expand_SPACESHIP (internal_fn, gcall *stmt)
    5664              : {
    5665          333 :   tree lhs = gimple_call_lhs (stmt);
    5666          333 :   tree rhs1 = gimple_call_arg (stmt, 0);
    5667          333 :   tree rhs2 = gimple_call_arg (stmt, 1);
    5668          333 :   tree rhs3 = gimple_call_arg (stmt, 2);
    5669          333 :   tree type = TREE_TYPE (rhs1);
    5670              : 
    5671          333 :   do_pending_stack_adjust ();
    5672              : 
    5673          333 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5674          333 :   rtx op1 = expand_normal (rhs1);
    5675          333 :   rtx op2 = expand_normal (rhs2);
    5676          333 :   rtx op3 = expand_normal (rhs3);
    5677              : 
    5678          333 :   class expand_operand ops[4];
    5679          333 :   create_call_lhs_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (lhs)));
    5680          333 :   create_input_operand (&ops[1], op1, TYPE_MODE (type));
    5681          333 :   create_input_operand (&ops[2], op2, TYPE_MODE (type));
    5682          333 :   create_input_operand (&ops[3], op3, TYPE_MODE (TREE_TYPE (rhs3)));
    5683          333 :   insn_code icode = optab_handler (spaceship_optab, TYPE_MODE (type));
    5684          333 :   expand_insn (icode, 4, ops);
    5685          333 :   assign_call_lhs (lhs, target, &ops[0]);
    5686          333 : }
    5687              : 
    5688              : void
    5689            0 : expand_ASSUME (internal_fn, gcall *)
    5690              : {
    5691            0 : }
    5692              : 
    5693              : void
    5694            0 : expand_MASK_CALL (internal_fn, gcall *)
    5695              : {
    5696              :   /* This IFN should only exist between ifcvt and vect passes.  */
    5697            0 :   gcc_unreachable ();
    5698              : }
    5699              : 
    5700              : void
    5701            0 : expand_VARYING (internal_fn, gcall *)
    5702              : {
    5703              :   /* This IFN should reach expand.  */
    5704            0 :   gcc_unreachable ();
    5705              : }
    5706              : 
    5707              : void
    5708         1689 : expand_MULBITINT (internal_fn, gcall *stmt)
    5709              : {
    5710         1689 :   rtx_mode_t args[6];
    5711        11823 :   for (int i = 0; i < 6; i++)
    5712        10134 :     args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
    5713        20268 :                           (i & 1) ? SImode : ptr_mode);
    5714         1689 :   rtx fun = init_one_libfunc ("__mulbitint3");
    5715         1689 :   emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 6, args);
    5716         1689 : }
    5717              : 
    5718              : void
    5719          163 : expand_DIVMODBITINT (internal_fn, gcall *stmt)
    5720              : {
    5721          163 :   rtx_mode_t args[8];
    5722         1467 :   for (int i = 0; i < 8; i++)
    5723         1304 :     args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
    5724         2608 :                           (i & 1) ? SImode : ptr_mode);
    5725          163 :   rtx fun = init_one_libfunc ("__divmodbitint4");
    5726          163 :   emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 8, args);
    5727          163 : }
    5728              : 
    5729              : void
    5730          179 : expand_FLOATTOBITINT (internal_fn, gcall *stmt)
    5731              : {
    5732          179 :   machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_call_arg (stmt, 2)));
    5733          179 :   rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
    5734          179 :   rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
    5735          179 :   rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
    5736          179 :   rtx fun = optab_libfunc (bitintfromfp_optab, mode);
    5737          179 :   emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
    5738              :                      SImode, arg2, mode);
    5739          179 : }
    5740              : 
    5741              : void
    5742          148 : expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
    5743              : {
    5744          148 :   tree lhs = gimple_call_lhs (stmt);
    5745          148 :   if (!lhs)
    5746              :     return;
    5747          148 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
    5748          148 :   rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
    5749          148 :   rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
    5750          148 :   rtx fun = optab_libfunc (bitinttofp_optab, mode);
    5751          148 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5752          148 :   rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
    5753              :                                      arg0, ptr_mode, arg1, SImode);
    5754          148 :   if (val != target)
    5755            0 :     emit_move_insn (target, val);
    5756              : }
    5757              : 
    5758              : static bool
    5759         6443 : expand_bitquery (internal_fn fn, gcall *stmt)
    5760              : {
    5761         6443 :   tree lhs = gimple_call_lhs (stmt);
    5762         6443 :   if (lhs == NULL_TREE)
    5763              :     return false;
    5764         6437 :   tree arg = gimple_call_arg (stmt, 0);
    5765         6437 :   if (TREE_CODE (arg) == INTEGER_CST)
    5766              :     {
    5767            0 :       tree ret = fold_const_call (as_combined_fn (fn), TREE_TYPE (arg), arg);
    5768            0 :       gcc_checking_assert (ret && TREE_CODE (ret) == INTEGER_CST);
    5769            0 :       expand_assignment (lhs, ret, false);
    5770            0 :       return false;
    5771              :     }
    5772              :   return true;
    5773              : }
    5774              : 
    5775              : void
    5776            1 : expand_CLRSB (internal_fn fn, gcall *stmt)
    5777              : {
    5778            1 :   if (expand_bitquery (fn, stmt))
    5779            0 :     expand_unary_optab_fn (fn, stmt, clrsb_optab);
    5780            1 : }
    5781              : 
    5782              : void
    5783         4733 : expand_CLZ (internal_fn fn, gcall *stmt)
    5784              : {
    5785         4733 :   if (expand_bitquery (fn, stmt))
    5786         4732 :     expand_unary_optab_fn (fn, stmt, clz_optab);
    5787         4733 : }
    5788              : 
    5789              : void
    5790         1186 : expand_CTZ (internal_fn fn, gcall *stmt)
    5791              : {
    5792         1186 :   if (expand_bitquery (fn, stmt))
    5793         1185 :     expand_unary_optab_fn (fn, stmt, ctz_optab);
    5794         1186 : }
    5795              : 
    5796              : void
    5797          133 : expand_FFS (internal_fn fn, gcall *stmt)
    5798              : {
    5799          133 :   if (expand_bitquery (fn, stmt))
    5800          132 :     expand_unary_optab_fn (fn, stmt, ffs_optab);
    5801          133 : }
    5802              : 
    5803              : void
    5804          173 : expand_PARITY (internal_fn fn, gcall *stmt)
    5805              : {
    5806          173 :   if (expand_bitquery (fn, stmt))
    5807          172 :     expand_unary_optab_fn (fn, stmt, parity_optab);
    5808          173 : }
    5809              : 
    5810              : void
    5811          217 : expand_POPCOUNT (internal_fn fn, gcall *stmt)
    5812              : {
    5813          217 :   if (!expand_bitquery (fn, stmt))
    5814              :     return;
    5815          216 :   if (gimple_call_num_args (stmt) == 1)
    5816              :     {
    5817          208 :       expand_unary_optab_fn (fn, stmt, popcount_optab);
    5818          208 :       return;
    5819              :     }
    5820              :   /* If .POPCOUNT call has 2 arguments, match_single_bit_test marked it
    5821              :      because the result is only used in an equality comparison against 1.
    5822              :      Use rtx costs in that case to determine if .POPCOUNT (arg) == 1
    5823              :      or (arg ^ (arg - 1)) > arg - 1 is cheaper.
    5824              :      If .POPCOUNT second argument is 0, we additionally know that arg
    5825              :      is non-zero, so use arg & (arg - 1) == 0 instead.
    5826              :      If .POPCOUNT second argument is -1, the comparison was either `<= 1`
    5827              :      or `> 1`.  */
    5828            8 :   bool speed_p = optimize_insn_for_speed_p ();
    5829            8 :   tree lhs = gimple_call_lhs (stmt);
    5830            8 :   tree arg = gimple_call_arg (stmt, 0);
    5831            8 :   bool nonzero_arg = integer_zerop (gimple_call_arg (stmt, 1));
    5832            8 :   bool was_le = integer_minus_onep (gimple_call_arg (stmt, 1));
    5833            8 :   if (was_le)
    5834            0 :     nonzero_arg = true;
    5835            8 :   tree type = TREE_TYPE (arg);
    5836            8 :   machine_mode mode = TYPE_MODE (type);
    5837            8 :   machine_mode lhsmode = TYPE_MODE (TREE_TYPE (lhs));
    5838            8 :   do_pending_stack_adjust ();
    5839            8 :   start_sequence ();
    5840            8 :   expand_unary_optab_fn (fn, stmt, popcount_optab);
    5841            8 :   rtx_insn *popcount_insns = end_sequence ();
    5842            8 :   start_sequence ();
    5843            8 :   rtx plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5844            8 :   rtx pcmp = emit_store_flag (NULL_RTX, EQ, plhs, const1_rtx, lhsmode, 0, 0);
    5845            8 :   if (pcmp == NULL_RTX)
    5846              :     {
    5847            0 :     fail:
    5848            0 :       end_sequence ();
    5849            0 :       emit_insn (popcount_insns);
    5850            0 :       return;
    5851              :     }
    5852            8 :   rtx_insn *popcount_cmp_insns = end_sequence ();
    5853            8 :   start_sequence ();
    5854            8 :   rtx op0 = expand_normal (arg);
    5855            8 :   rtx argm1 = expand_simple_binop (mode, PLUS, op0, constm1_rtx, NULL_RTX,
    5856              :                                    1, OPTAB_WIDEN);
    5857            8 :   if (argm1 == NULL_RTX)
    5858            0 :     goto fail;
    5859           12 :   rtx argxorargm1 = expand_simple_binop (mode, nonzero_arg ? AND : XOR, op0,
    5860              :                                          argm1, NULL_RTX, 1, OPTAB_WIDEN);
    5861            8 :   if (argxorargm1 == NULL_RTX)
    5862            0 :     goto fail;
    5863            8 :   rtx cmp;
    5864            8 :   if (nonzero_arg)
    5865            4 :     cmp = emit_store_flag (NULL_RTX, EQ, argxorargm1, const0_rtx, mode, 1, 1);
    5866              :   else
    5867            4 :     cmp = emit_store_flag (NULL_RTX, GTU, argxorargm1, argm1, mode, 1, 1);
    5868            8 :   if (cmp == NULL_RTX)
    5869            0 :     goto fail;
    5870            8 :   rtx_insn *cmp_insns = end_sequence ();
    5871            8 :   unsigned popcount_cost = (seq_cost (popcount_insns, speed_p)
    5872            8 :                             + seq_cost (popcount_cmp_insns, speed_p));
    5873            8 :   unsigned cmp_cost = seq_cost (cmp_insns, speed_p);
    5874              : 
    5875            8 :   if (dump_file && (dump_flags & TDF_DETAILS))
    5876            0 :     fprintf(dump_file, "popcount == 1: popcount cost: %u; cmp cost: %u\n",
    5877              :             popcount_cost, cmp_cost);
    5878              : 
    5879            8 :   if (popcount_cost <= cmp_cost)
    5880            8 :     emit_insn (popcount_insns);
    5881              :   else
    5882              :     {
    5883            0 :       start_sequence ();
    5884            0 :       emit_insn (cmp_insns);
    5885            0 :       plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5886            0 :       if (GET_MODE (cmp) != GET_MODE (plhs))
    5887            0 :         cmp = convert_to_mode (GET_MODE (plhs), cmp, 1);
    5888              :       /* For `<= 1`, we need to produce `2 - cmp` or `cmp ? 1 : 2` as that
    5889              :          then gets compared against 1 and we need the false case to be 2.  */
    5890            0 :       if (was_le)
    5891              :         {
    5892            0 :           cmp = expand_simple_binop (GET_MODE (cmp), MINUS, const2_rtx,
    5893              :                                      cmp, NULL_RTX, 1, OPTAB_WIDEN);
    5894            0 :           if (!cmp)
    5895            0 :             goto fail;
    5896              :         }
    5897            0 :       emit_move_insn (plhs, cmp);
    5898            0 :       rtx_insn *all_insns = end_sequence ();
    5899            0 :       emit_insn (all_insns);
    5900              :     }
    5901              : }
    5902              : 
    5903              : void
    5904            0 : expand_BSWAP (internal_fn fn, gcall *stmt)
    5905              : {
    5906            0 :   if (expand_bitquery (fn, stmt))
    5907            0 :     expand_unary_optab_fn (fn, stmt, bswap_optab);
    5908            0 : }
    5909              : 
    5910              : void
    5911            0 : expand_BITREVERSE (internal_fn fn, gcall *stmt)
    5912              : {
    5913            0 :   if (expand_bitquery (fn, stmt))
    5914            0 :     expand_unary_optab_fn (fn, stmt, bitreverse_optab);
    5915            0 : }
        

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