LCOV - code coverage report
Current view: top level - gcc - internal-fn.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.4 % 2505 1789
Test Date: 2026-02-28 14:20:25 Functions: 59.8 % 174 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 "gimple.h"
      29              : #include "predict.h"
      30              : #include "stringpool.h"
      31              : #include "tree-vrp.h"
      32              : #include "tree-ssanames.h"
      33              : #include "expmed.h"
      34              : #include "memmodel.h"
      35              : #include "optabs.h"
      36              : #include "emit-rtl.h"
      37              : #include "diagnostic-core.h"
      38              : #include "fold-const.h"
      39              : #include "internal-fn.h"
      40              : #include "stor-layout.h"
      41              : #include "dojump.h"
      42              : #include "expr.h"
      43              : #include "stringpool.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            5 : lookup_internal_fn (const char *name)
      83              : {
      84            5 :   typedef hash_map<nofree_string_hash, internal_fn> name_to_fn_map_type;
      85            5 :   static name_to_fn_map_type *name_to_fn_map;
      86              : 
      87            5 :   if (!name_to_fn_map)
      88              :     {
      89            3 :       name_to_fn_map = new name_to_fn_map_type (IFN_LAST);
      90          882 :       for (unsigned int i = 0; i < IFN_LAST; ++i)
      91         1758 :         name_to_fn_map->put (internal_fn_name (internal_fn (i)),
      92          879 :                              internal_fn (i));
      93              :     }
      94            5 :   internal_fn *entry = name_to_fn_map->get (name);
      95            5 :   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        52398 : lookup_hilo_internal_fn (internal_fn ifn, internal_fn *lo, internal_fn *hi)
     103              : {
     104        52398 :   gcc_assert (widening_fn_p (ifn));
     105              : 
     106        52398 :   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        52398 : }
     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        52398 : lookup_evenodd_internal_fn (internal_fn ifn, internal_fn *even,
     125              :                             internal_fn *odd)
     126              : {
     127        52398 :   gcc_assert (widening_fn_p (ifn));
     128              : 
     129        52398 :   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        52398 : }
     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       285405 : 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       285405 :   internal_fn_fnspec_array[IFN_LAST] = 0;
     155       285405 : }
     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        90178 : 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        90178 :   rtx dest = lhs_rtx;
     219        90178 :   if (dest && GET_CODE (dest) == SUBREG && SUBREG_PROMOTED_VAR_P (dest))
     220              :     dest = NULL_RTX;
     221        90178 :   create_output_operand (op, dest, mode);
     222        90178 : }
     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        90178 : assign_call_lhs (tree lhs, rtx lhs_rtx, expand_operand *op)
     231              : {
     232        90178 :   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         4334 :   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         4334 :   else if (GET_MODE (lhs_rtx) == GET_MODE (op->value))
     253           39 :     emit_move_insn (lhs_rtx, op->value);
     254              :   else
     255              :     {
     256         4295 :       gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs)));
     257         4295 :       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        80053 : expand_fn_using_insn (gcall *stmt, insn_code icode, unsigned int noutputs,
     268              :                       unsigned int ninputs)
     269              : {
     270        80053 :   gcc_assert (icode != CODE_FOR_nothing);
     271              : 
     272        80053 :   expand_operand *ops = XALLOCAVEC (expand_operand, noutputs + ninputs);
     273        80053 :   unsigned int opno = 0;
     274        80053 :   rtx lhs_rtx = NULL_RTX;
     275        80053 :   tree lhs = gimple_call_lhs (stmt);
     276              : 
     277        80053 :   if (noutputs)
     278              :     {
     279        80053 :       gcc_assert (noutputs == 1);
     280        80053 :       if (lhs)
     281        80053 :         lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
     282        80053 :       create_call_lhs_operand (&ops[opno], lhs_rtx,
     283        80053 :                                insn_data[icode].operand[opno].mode);
     284        80053 :       opno += 1;
     285              :     }
     286              :   else
     287            0 :     gcc_assert (!lhs);
     288              : 
     289       225302 :   for (unsigned int i = 0; i < ninputs; ++i)
     290              :     {
     291       145249 :       tree rhs = gimple_call_arg (stmt, i);
     292       145249 :       tree rhs_type = TREE_TYPE (rhs);
     293       145249 :       rtx rhs_rtx = expand_normal (rhs);
     294       145249 :       if (INTEGRAL_TYPE_P (rhs_type))
     295         7646 :         create_convert_operand_from (&ops[opno], rhs_rtx,
     296         7646 :                                      TYPE_MODE (rhs_type),
     297         7646 :                                      TYPE_UNSIGNED (rhs_type));
     298       137603 :       else if (TREE_CODE (rhs) == SSA_NAME
     299       112921 :                && SSA_NAME_IS_DEFAULT_DEF (rhs)
     300       142037 :                && VAR_P (SSA_NAME_VAR (rhs)))
     301          249 :         create_undefined_input_operand (&ops[opno], TYPE_MODE (rhs_type));
     302        57177 :       else if (VECTOR_BOOLEAN_TYPE_P (rhs_type)
     303         1531 :                && SCALAR_INT_MODE_P (TYPE_MODE (rhs_type))
     304       138885 :                && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (rhs_type)),
     305         1531 :                             TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ()))
     306              :         {
     307              :           /* Ensure that the vector bitmasks do not have excess bits.  */
     308          432 :           int nunits = TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ();
     309          432 :           rtx tmp = expand_binop (TYPE_MODE (rhs_type), and_optab, rhs_rtx,
     310          432 :                                   GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
     311              :                                   NULL_RTX, true, OPTAB_WIDEN);
     312          432 :           create_input_operand (&ops[opno], tmp, TYPE_MODE (rhs_type));
     313              :         }
     314              :       else
     315       136922 :         create_input_operand (&ops[opno], rhs_rtx, TYPE_MODE (rhs_type));
     316       145249 :       opno += 1;
     317              :     }
     318              : 
     319        80053 :   gcc_assert (opno == noutputs + ninputs);
     320        80053 :   expand_insn (icode, opno, ops);
     321        80053 :   if (lhs_rtx)
     322        80053 :     assign_call_lhs (lhs, lhs_rtx, &ops[0]);
     323        80053 : }
     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         1479 : add_mask_else_and_len_args (expand_operand *ops, unsigned int opno, gcall *stmt)
     345              : {
     346         1479 :   internal_fn ifn = gimple_call_internal_fn (stmt);
     347         1479 :   int len_index = internal_fn_len_index (ifn);
     348              :   /* BIAS is always consecutive next of LEN.  */
     349         1479 :   int bias_index = len_index + 1;
     350         1479 :   int mask_index = internal_fn_mask_index (ifn);
     351              : 
     352              :   /* The order of arguments is always {mask, else, len, bias}.  */
     353         1479 :   if (mask_index >= 0)
     354              :     {
     355         1479 :       tree mask = gimple_call_arg (stmt, mask_index);
     356         1479 :       rtx mask_rtx = expand_normal (mask);
     357              : 
     358         1479 :       tree mask_type = TREE_TYPE (mask);
     359         1479 :       if (VECTOR_BOOLEAN_TYPE_P (mask_type)
     360         1479 :           && SCALAR_INT_MODE_P (TYPE_MODE (mask_type))
     361         2515 :           && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (mask_type)),
     362         2294 :                        TYPE_VECTOR_SUBPARTS (mask_type).to_constant ()))
     363              :         {
     364              :           /* Ensure that the vector bitmasks do not have excess bits.  */
     365          221 :           int nunits = TYPE_VECTOR_SUBPARTS (mask_type).to_constant ();
     366          221 :           mask_rtx = expand_binop (TYPE_MODE (mask_type), and_optab, mask_rtx,
     367          221 :                                    GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
     368              :                                    NULL_RTX, true, OPTAB_WIDEN);
     369              :         }
     370              : 
     371         1479 :       create_input_operand (&ops[opno++], mask_rtx,
     372         1479 :                             TYPE_MODE (TREE_TYPE (mask)));
     373              :     }
     374              : 
     375         1479 :   int els_index = internal_fn_else_index (ifn);
     376         1479 :   if (els_index >= 0)
     377              :     {
     378          721 :       tree els = gimple_call_arg (stmt, els_index);
     379          721 :       tree els_type = TREE_TYPE (els);
     380          721 :       if (TREE_CODE (els) == SSA_NAME
     381            0 :           && SSA_NAME_IS_DEFAULT_DEF (els)
     382          721 :           && VAR_P (SSA_NAME_VAR (els)))
     383            0 :         create_undefined_input_operand (&ops[opno++], TYPE_MODE (els_type));
     384              :       else
     385              :         {
     386          721 :           rtx els_rtx = expand_normal (els);
     387          721 :           create_input_operand (&ops[opno++], els_rtx, TYPE_MODE (els_type));
     388              :         }
     389              :     }
     390         1479 :   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         1479 :   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       155782 : get_min_precision (tree arg, signop sign)
     966              : {
     967       155782 :   int prec = TYPE_PRECISION (TREE_TYPE (arg));
     968       155782 :   int cnt = 0;
     969       155782 :   signop orig_sign = sign;
     970       155782 :   if (TREE_CODE (arg) == INTEGER_CST)
     971              :     {
     972        40555 :       int p;
     973        40555 :       if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
     974              :         {
     975        14465 :           widest_int w = wi::to_widest (arg);
     976        14465 :           w = wi::ext (w, prec, sign);
     977        14465 :           p = wi::min_precision (w, sign);
     978        14465 :         }
     979              :       else
     980        26090 :         p = wi::min_precision (wi::to_wide (arg), sign);
     981        40555 :       return MIN (p, prec);
     982              :     }
     983       115167 :   while (CONVERT_EXPR_P (arg)
     984         6563 :          && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
     985       128293 :          && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
     986              :     {
     987         6503 :       arg = TREE_OPERAND (arg, 0);
     988         6503 :       if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
     989              :         {
     990          342 :           if (TYPE_UNSIGNED (TREE_TYPE (arg)))
     991              :             sign = UNSIGNED;
     992          319 :           else if (sign == UNSIGNED
     993          319 :                    && (get_range_pos_neg (arg,
     994              :                                           currently_expanding_gimple_stmt)
     995              :                        != 1))
     996            0 :             return prec + (orig_sign != sign);
     997          342 :           prec = TYPE_PRECISION (TREE_TYPE (arg));
     998              :         }
     999         6503 :       if (++cnt > 30)
    1000            0 :         return prec + (orig_sign != sign);
    1001              :     }
    1002       115167 :   if (CONVERT_EXPR_P (arg)
    1003           60 :       && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
    1004       115287 :       && 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           60 :       int oprec = get_min_precision (TREE_OPERAND (arg, 0), sign);
    1009           60 :       if (oprec < prec)
    1010           60 :         return oprec + (orig_sign != sign);
    1011              :     }
    1012       115167 :   if (TREE_CODE (arg) != SSA_NAME)
    1013            0 :     return prec + (orig_sign != sign);
    1014       115167 :   int_range_max r;
    1015       115167 :   gimple *cg = currently_expanding_gimple_stmt;
    1016       230663 :   while (!get_range_query (cfun)->range_of_expr (r, arg, cg)
    1017       115496 :          || r.varying_p ()
    1018       258114 :          || r.undefined_p ())
    1019              :     {
    1020        88375 :       gimple *g = SSA_NAME_DEF_STMT (arg);
    1021        88375 :       if (is_gimple_assign (g)
    1022        88375 :           && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
    1023              :         {
    1024         1319 :           tree t = gimple_assign_rhs1 (g);
    1025         2638 :           if (INTEGRAL_TYPE_P (TREE_TYPE (t))
    1026         1670 :               && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
    1027              :             {
    1028          329 :               arg = t;
    1029          329 :               if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
    1030              :                 {
    1031            0 :                   if (TYPE_UNSIGNED (TREE_TYPE (arg)))
    1032              :                     sign = UNSIGNED;
    1033            0 :                   else if (sign == UNSIGNED
    1034            0 :                            && get_range_pos_neg (arg, g) != 1)
    1035            0 :                     return prec + (orig_sign != sign);
    1036            0 :                   prec = TYPE_PRECISION (TREE_TYPE (arg));
    1037              :                 }
    1038          329 :               if (++cnt > 30)
    1039            0 :                 return prec + (orig_sign != sign);
    1040          329 :               continue;
    1041              :             }
    1042              :         }
    1043        88046 :       return prec + (orig_sign != sign);
    1044              :     }
    1045        27121 :   if (sign == TYPE_SIGN (TREE_TYPE (arg)))
    1046              :     {
    1047        19833 :       int p1 = wi::min_precision (r.lower_bound (), sign);
    1048        19833 :       int p2 = wi::min_precision (r.upper_bound (), sign);
    1049        19833 :       p1 = MAX (p1, p2);
    1050        19833 :       prec = MIN (prec, p1);
    1051              :     }
    1052        14473 :   else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
    1053              :     {
    1054         7181 :       int p = wi::min_precision (r.upper_bound (), UNSIGNED);
    1055         7288 :       prec = MIN (prec, p);
    1056              :     }
    1057        27121 :   return prec + (orig_sign != sign);
    1058       115167 : }
    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        80568 : expand_arith_set_overflow (tree lhs, rtx target)
    1065              : {
    1066        80568 :   if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
    1067        80568 :       && !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
    1068          194 :     write_complex_part (target, constm1_rtx, true, false);
    1069              :   else
    1070        80374 :     write_complex_part (target, const1_rtx, true, false);
    1071        80568 : }
    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        71935 : expand_arith_overflow_result_store (tree lhs, rtx target,
    1080              :                                     scalar_int_mode mode, rtx res)
    1081              : {
    1082        71935 :   scalar_int_mode tgtmode
    1083       143870 :     = as_a <scalar_int_mode> (GET_MODE_INNER (GET_MODE (target)));
    1084        71935 :   rtx lres = res;
    1085        71935 :   if (tgtmode != mode)
    1086              :     {
    1087        17934 :       rtx_code_label *done_label = gen_label_rtx ();
    1088        17934 :       int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
    1089        17934 :       lres = convert_modes (tgtmode, mode, res, uns);
    1090        17934 :       gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
    1091        17934 :       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        17934 :       expand_arith_set_overflow (lhs, target);
    1095        17934 :       emit_label (done_label);
    1096              :     }
    1097        71935 :   int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
    1098        71935 :   int tgtprec = GET_MODE_PRECISION (tgtmode);
    1099        71935 :   if (prec < tgtprec)
    1100              :     {
    1101         3543 :       rtx_code_label *done_label = gen_label_rtx ();
    1102         3543 :       int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
    1103         3543 :       res = lres;
    1104         3543 :       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         1535 :           lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
    1115              :                                NULL_RTX, 1);
    1116         1535 :           lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
    1117              :                                NULL_RTX, 0);
    1118              :         }
    1119         3543 :       do_compare_rtx_and_jump (res, lres,
    1120              :                                EQ, true, tgtmode, NULL_RTX, NULL, done_label,
    1121              :                                profile_probability::very_likely ());
    1122         3543 :       expand_arith_set_overflow (lhs, target);
    1123         3543 :       emit_label (done_label);
    1124              :     }
    1125        71935 :   write_complex_part (target, lres, false, false);
    1126        71935 : }
    1127              : 
    1128              : /* Helper for expand_*_overflow.  Store RES into TARGET.  */
    1129              : 
    1130              : static void
    1131         4659 : expand_ubsan_result_store (tree lhs, rtx target, scalar_int_mode mode,
    1132              :                            rtx res, rtx_code_label *do_error)
    1133              : {
    1134         4659 :   if (TREE_CODE (TREE_TYPE (lhs)) == BITINT_TYPE
    1135         4659 :       && 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         4659 :   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         4659 :     emit_move_insn (target, res);
    1171         4659 : }
    1172              : 
    1173              : /* Add sub/add overflow checking to the statement STMT.
    1174              :    CODE says whether the operation is +, or -.  */
    1175              : 
    1176              : void
    1177        39620 : 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        39620 :   rtx res, target = NULL_RTX;
    1182        39620 :   tree fn;
    1183        39620 :   rtx_code_label *done_label = gen_label_rtx ();
    1184        39620 :   rtx_code_label *do_error = gen_label_rtx ();
    1185        39620 :   do_pending_stack_adjust ();
    1186        39620 :   rtx op0 = expand_normal (arg0);
    1187        39620 :   rtx op1 = expand_normal (arg1);
    1188        39620 :   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
    1189        39620 :   int prec = GET_MODE_PRECISION (mode);
    1190        39620 :   rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
    1191        39620 :   bool do_xor = false;
    1192              : 
    1193        39620 :   if (is_ubsan)
    1194         3386 :     gcc_assert (!unsr_p && !uns0_p && !uns1_p);
    1195              : 
    1196        39620 :   if (lhs)
    1197              :     {
    1198        39092 :       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    1199        39092 :       if (!is_ubsan)
    1200        36234 :         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        39620 :   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        38785 :   if (uns0_p && uns1_p && unsr_p)
    1274              :     {
    1275        21504 :       insn_code icode = optab_handler (code == PLUS_EXPR ? uaddv4_optab
    1276              :                                        : usubv4_optab, mode);
    1277        16064 :       if (icode != CODE_FOR_nothing)
    1278              :         {
    1279        15159 :           class expand_operand ops[4];
    1280        15159 :           rtx_insn *last = get_last_insn ();
    1281              : 
    1282        15159 :           res = gen_reg_rtx (mode);
    1283        15159 :           create_output_operand (&ops[0], res, mode);
    1284        15159 :           create_input_operand (&ops[1], op0, mode);
    1285        15159 :           create_input_operand (&ops[2], op1, mode);
    1286        15159 :           create_fixed_operand (&ops[3], do_error);
    1287        15159 :           if (maybe_expand_insn (icode, 4, ops))
    1288              :             {
    1289        15159 :               last = get_last_insn ();
    1290        15159 :               if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    1291        12564 :                   && JUMP_P (last)
    1292        12564 :                   && any_condjump_p (last)
    1293        27723 :                   && !find_reg_note (last, REG_BR_PROB, 0))
    1294        12564 :                 add_reg_br_prob_note (last,
    1295              :                                       profile_probability::very_unlikely ());
    1296        15159 :               emit_jump (done_label);
    1297        15159 :               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         1810 :       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1306              :                           op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1307          905 :       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          905 :       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          905 :         tem = op1;
    1320         1810 :       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          905 :       goto do_error_label;
    1324              :     }
    1325              : 
    1326              :   /* s1 +- u2 -> sr  */
    1327        23556 :   if (!uns0_p && uns1_p && !unsr_p)
    1328              :     {
    1329              :       /* Compute the operation.  On RTL level, the addition is always
    1330              :          unsigned.  */
    1331         2111 :       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1332              :                           op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1333         2111 :       rtx tem = expand_binop (mode, add_optab,
    1334              :                               code == PLUS_EXPR ? res : op0, sgn,
    1335              :                               NULL_RTX, false, OPTAB_LIB_WIDEN);
    1336         1309 :       do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL,
    1337              :                                done_label, profile_probability::very_likely ());
    1338         1309 :       goto do_error_label;
    1339              :     }
    1340              : 
    1341              :   /* s1 + u2 -> ur  */
    1342        22247 :   if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
    1343              :     {
    1344         1919 :       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         1919 :       arg1 = error_mark_node;
    1349         1919 :       do_xor = true;
    1350         1919 :       goto do_signed;
    1351              :     }
    1352              : 
    1353              :   /* u1 - s2 -> ur  */
    1354        20328 :   if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
    1355              :     {
    1356          820 :       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          820 :       arg0 = error_mark_node;
    1361          820 :       do_xor = true;
    1362          820 :       goto do_signed;
    1363              :     }
    1364              : 
    1365              :   /* s1 - u2 -> ur  */
    1366        19508 :   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         1358 :       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
    1371              :                           OPTAB_LIB_WIDEN);
    1372         1358 :       int pos_neg = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
    1373         1358 :       if (pos_neg == 2)
    1374              :         /* If ARG0 is known to be always negative, this is always overflow.  */
    1375          148 :         emit_jump (do_error);
    1376         1210 :       else if (pos_neg == 3)
    1377              :         /* If ARG0 is not known to be always positive, check at runtime.  */
    1378         1210 :         do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX,
    1379              :                                  NULL, do_error, profile_probability::very_unlikely ());
    1380         1358 :       do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL,
    1381              :                                done_label, profile_probability::very_likely ());
    1382         1358 :       goto do_error_label;
    1383              :     }
    1384              : 
    1385              :   /* u1 - s2 -> sr  */
    1386        18150 :   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          390 :       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
    1391              :                           OPTAB_LIB_WIDEN);
    1392          390 :       rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
    1393              :                               OPTAB_LIB_WIDEN);
    1394          390 :       do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL,
    1395              :                                done_label, profile_probability::very_likely ());
    1396          390 :       goto do_error_label;
    1397              :     }
    1398              : 
    1399              :   /* u1 + u2 -> sr  */
    1400        17760 :   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         1393 :       res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false,
    1405              :                           OPTAB_LIB_WIDEN);
    1406         1393 :       do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
    1407              :                                NULL, do_error, profile_probability::very_unlikely ());
    1408         1393 :       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         1393 :       if (prec <= BITS_PER_WORD
    1417         1393 :           ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
    1418          448 :           : CONST_SCALAR_INT_P (op0))
    1419         1393 :         tem = op0;
    1420         1393 :       do_compare_rtx_and_jump (res, tem, GEU, true, mode, NULL_RTX, NULL,
    1421              :                                done_label, profile_probability::very_likely ());
    1422         1393 :       goto do_error_label;
    1423              :     }
    1424              : 
    1425              :   /* s1 +- s2 -> ur  */
    1426        16367 :   if (!uns0_p && !uns1_p && unsr_p)
    1427              :     {
    1428              :       /* Compute the operation.  On RTL level, the addition is always
    1429              :          unsigned.  */
    1430         3516 :       res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
    1431              :                           op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
    1432         2359 :       int pos_neg = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
    1433         2359 :       if (code == PLUS_EXPR)
    1434              :         {
    1435         1202 :           int pos_neg0 = get_range_pos_neg (arg0,
    1436              :                                             currently_expanding_gimple_stmt);
    1437         1202 :           if (pos_neg0 != 3 && pos_neg == 3)
    1438              :             {
    1439              :               std::swap (op0, op1);
    1440              :               pos_neg = pos_neg0;
    1441              :             }
    1442              :         }
    1443         2290 :       rtx tem;
    1444         2290 :       if (pos_neg != 3)
    1445              :         {
    1446         1941 :           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         1161 :           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         1198 :           rtx_code_label *do_ior_label = gen_label_rtx ();
    1455         1620 :           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         1198 :           tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
    1460              :                               OPTAB_LIB_WIDEN);
    1461         1198 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    1462              :                                    NULL, done_label, profile_probability::very_likely ());
    1463         1198 :           emit_jump (do_error);
    1464         1198 :           emit_label (do_ior_label);
    1465         1198 :           tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
    1466              :                               OPTAB_LIB_WIDEN);
    1467         1198 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    1468              :                                    NULL, done_label, profile_probability::very_likely ());
    1469              :         }
    1470         2359 :       goto do_error_label;
    1471              :     }
    1472              : 
    1473              :   /* u1 - u2 -> sr  */
    1474        14008 :   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         1960 :       res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
    1479              :                           OPTAB_LIB_WIDEN);
    1480         1960 :       rtx_code_label *op0_geu_op1 = gen_label_rtx ();
    1481         1960 :       do_compare_rtx_and_jump (op0, op1, GEU, true, mode, NULL_RTX, NULL,
    1482              :                                op0_geu_op1, profile_probability::even ());
    1483         1960 :       do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
    1484              :                                NULL, done_label, profile_probability::very_likely ());
    1485         1960 :       emit_jump (do_error);
    1486         1960 :       emit_label (op0_geu_op1);
    1487         1960 :       do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
    1488              :                                NULL, done_label, profile_probability::very_likely ());
    1489         1960 :       goto do_error_label;
    1490              :     }
    1491              : 
    1492        12048 :   gcc_assert (!uns0_p && !uns1_p && !unsr_p);
    1493              : 
    1494              :   /* s1 +- s2 -> sr  */
    1495        12048 :  do_signed:
    1496        14787 :   {
    1497        21411 :     insn_code icode = optab_handler (code == PLUS_EXPR ? addv4_optab
    1498              :                                      : subv4_optab, mode);
    1499        14787 :     if (icode != CODE_FOR_nothing)
    1500              :       {
    1501        14787 :         class expand_operand ops[4];
    1502        14787 :         rtx_insn *last = get_last_insn ();
    1503              : 
    1504        14787 :         res = gen_reg_rtx (mode);
    1505        14787 :         create_output_operand (&ops[0], res, mode);
    1506        14787 :         create_input_operand (&ops[1], op0, mode);
    1507        14787 :         create_input_operand (&ops[2], op1, mode);
    1508        14787 :         create_fixed_operand (&ops[3], do_error);
    1509        14787 :         if (maybe_expand_insn (icode, 4, ops))
    1510              :           {
    1511        14787 :             last = get_last_insn ();
    1512        14787 :             if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    1513         9587 :                 && JUMP_P (last)
    1514         9587 :                 && any_condjump_p (last)
    1515        24374 :                 && !find_reg_note (last, REG_BR_PROB, 0))
    1516         9587 :               add_reg_br_prob_note (last,
    1517              :                                     profile_probability::very_unlikely ());
    1518        14787 :             emit_jump (done_label);
    1519        14787 :             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        39620 :  do_error_label:
    1593        39620 :   emit_label (do_error);
    1594        39620 :   if (is_ubsan)
    1595              :     {
    1596              :       /* Expand the ubsan builtin call.  */
    1597         3386 :       push_temp_slots ();
    1598         3386 :       fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
    1599              :                                          arg0, arg1, datap);
    1600         3386 :       expand_normal (fn);
    1601         3386 :       pop_temp_slots ();
    1602         3386 :       do_pending_stack_adjust ();
    1603              :     }
    1604        36234 :   else if (lhs)
    1605        36234 :     expand_arith_set_overflow (lhs, target);
    1606              : 
    1607              :   /* We're done.  */
    1608        39620 :   emit_label (done_label);
    1609              : 
    1610        39620 :   if (lhs)
    1611              :     {
    1612        39092 :       if (is_ubsan)
    1613         2858 :         expand_ubsan_result_store (lhs, target, mode, res, do_error);
    1614              :       else
    1615              :         {
    1616        36234 :           if (do_xor)
    1617         2739 :             res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
    1618              :                                 OPTAB_LIB_WIDEN);
    1619              : 
    1620        36234 :           expand_arith_overflow_result_store (lhs, target, mode, res);
    1621              :         }
    1622              :     }
    1623        39620 : }
    1624              : 
    1625              : /* Add negate overflow checking to the statement STMT.  */
    1626              : 
    1627              : static void
    1628          973 : expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan,
    1629              :                      tree *datap)
    1630              : {
    1631          973 :   rtx res, op1;
    1632          973 :   tree fn;
    1633          973 :   rtx_code_label *done_label, *do_error;
    1634          973 :   rtx target = NULL_RTX;
    1635              : 
    1636          973 :   done_label = gen_label_rtx ();
    1637          973 :   do_error = gen_label_rtx ();
    1638              : 
    1639          973 :   do_pending_stack_adjust ();
    1640          973 :   op1 = expand_normal (arg1);
    1641              : 
    1642          973 :   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg1));
    1643          973 :   if (lhs)
    1644              :     {
    1645          841 :       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    1646          841 :       if (!is_ubsan)
    1647          402 :         write_complex_part (target, const0_rtx, true, false);
    1648              :     }
    1649              : 
    1650          973 :   enum insn_code icode = optab_handler (negv3_optab, mode);
    1651          973 :   if (icode != CODE_FOR_nothing)
    1652              :     {
    1653          895 :       class expand_operand ops[3];
    1654          895 :       rtx_insn *last = get_last_insn ();
    1655              : 
    1656          895 :       res = gen_reg_rtx (mode);
    1657          895 :       create_output_operand (&ops[0], res, mode);
    1658          895 :       create_input_operand (&ops[1], op1, mode);
    1659          895 :       create_fixed_operand (&ops[2], do_error);
    1660          895 :       if (maybe_expand_insn (icode, 3, ops))
    1661              :         {
    1662          895 :           last = get_last_insn ();
    1663          895 :           if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    1664          606 :               && JUMP_P (last)
    1665          606 :               && any_condjump_p (last)
    1666         1501 :               && !find_reg_note (last, REG_BR_PROB, 0))
    1667          606 :             add_reg_br_prob_note (last,
    1668              :                                   profile_probability::very_unlikely ());
    1669          895 :           emit_jump (done_label);
    1670              :         }
    1671              :       else
    1672              :         {
    1673            0 :           delete_insns_since (last);
    1674            0 :           icode = CODE_FOR_nothing;
    1675              :         }
    1676              :     }
    1677              : 
    1678          895 :   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          973 :   emit_label (do_error);
    1691          973 :   if (is_ubsan)
    1692              :     {
    1693              :       /* Expand the ubsan builtin call.  */
    1694          571 :       push_temp_slots ();
    1695          571 :       fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
    1696              :                                          arg1, NULL_TREE, datap);
    1697          571 :       expand_normal (fn);
    1698          571 :       pop_temp_slots ();
    1699          571 :       do_pending_stack_adjust ();
    1700              :     }
    1701          402 :   else if (lhs)
    1702          402 :     expand_arith_set_overflow (lhs, target);
    1703              : 
    1704              :   /* We're done.  */
    1705          973 :   emit_label (done_label);
    1706              : 
    1707          973 :   if (lhs)
    1708              :     {
    1709          841 :       if (is_ubsan)
    1710          439 :         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          973 : }
    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        18504 : 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        18504 :   rtx res, op0, op1;
    1753        18504 :   tree fn, type;
    1754        18504 :   rtx_code_label *done_label, *do_error;
    1755        18504 :   rtx target = NULL_RTX;
    1756        18504 :   signop sign;
    1757        18504 :   enum insn_code icode;
    1758        18504 :   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        18504 :   flag_trapv = 0;
    1763        18504 :   done_label = gen_label_rtx ();
    1764        18504 :   do_error = gen_label_rtx ();
    1765              : 
    1766        18504 :   do_pending_stack_adjust ();
    1767        18504 :   op0 = expand_normal (arg0);
    1768        18504 :   op1 = expand_normal (arg1);
    1769              : 
    1770        18504 :   scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
    1771        18504 :   bool uns = unsr_p;
    1772        18504 :   if (lhs)
    1773              :     {
    1774        18360 :       target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    1775        18360 :       if (!is_ubsan)
    1776        16998 :         write_complex_part (target, const0_rtx, true, false);
    1777              :     }
    1778              : 
    1779        17142 :   if (is_ubsan)
    1780         1506 :     gcc_assert (!unsr_p && !uns0_p && !uns1_p);
    1781              : 
    1782              :   /* We assume both operands and result have the same precision
    1783              :      here (GET_MODE_BITSIZE (mode)), S stands for signed type
    1784              :      with that precision, U for unsigned type with that precision,
    1785              :      sgn for unsigned most significant bit in that precision.
    1786              :      s1 is signed first operand, u1 is unsigned first operand,
    1787              :      s2 is signed second operand, u2 is unsigned second operand,
    1788              :      sr is signed result, ur is unsigned result and the following
    1789              :      rules say how to compute result (which is always result of
    1790              :      the operands as if both were unsigned, cast to the right
    1791              :      signedness) and how to compute whether operation overflowed.
    1792              :      main_ovf (false) stands for jump on signed multiplication
    1793              :      overflow or the main algorithm with uns == false.
    1794              :      main_ovf (true) stands for jump on unsigned multiplication
    1795              :      overflow or the main algorithm with uns == true.
    1796              : 
    1797              :      s1 * s2 -> sr
    1798              :         res = (S) ((U) s1 * (U) s2)
    1799              :         ovf = main_ovf (false)
    1800              :      u1 * u2 -> ur
    1801              :         res = u1 * u2
    1802              :         ovf = main_ovf (true)
    1803              :      s1 * u2 -> ur
    1804              :         res = (U) s1 * u2
    1805              :         ovf = (s1 < 0 && u2) || main_ovf (true)
    1806              :      u1 * u2 -> sr
    1807              :         res = (S) (u1 * u2)
    1808              :         ovf = res < 0 || main_ovf (true)
    1809              :      s1 * u2 -> sr
    1810              :         res = (S) ((U) s1 * u2)
    1811              :         ovf = (S) u2 >= 0 ? main_ovf (false)
    1812              :                           : (s1 != 0 && (s1 != -1 || u2 != (U) res))
    1813              :      s1 * s2 -> ur
    1814              :         t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
    1815              :         t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
    1816              :         res = t1 * t2
    1817              :         ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true)  */
    1818              : 
    1819        18504 :   if (uns0_p && !uns1_p)
    1820              :     {
    1821              :       /* Multiplication is commutative, if operand signedness differs,
    1822              :          canonicalize to the first operand being signed and second
    1823              :          unsigned to simplify following code.  */
    1824         1479 :       std::swap (op0, op1);
    1825         1479 :       std::swap (arg0, arg1);
    1826         1479 :       uns0_p = false;
    1827         1479 :       uns1_p = true;
    1828              :     }
    1829              : 
    1830        18504 :   int pos_neg0 = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
    1831        18504 :   int pos_neg1 = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
    1832              :   /* Unsigned types with smaller than mode precision, even if they have most
    1833              :      significant bit set, are still zero-extended.  */
    1834        18504 :   if (uns0_p && TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
    1835              :     pos_neg0 = 1;
    1836        18504 :   if (uns1_p && TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
    1837              :     pos_neg1 = 1;
    1838              : 
    1839              :   /* s1 * u2 -> ur  */
    1840        18504 :   if (!uns0_p && uns1_p && unsr_p)
    1841              :     {
    1842         2403 :       switch (pos_neg0)
    1843              :         {
    1844            0 :         case 1:
    1845              :           /* If s1 is non-negative, just perform normal u1 * u2 -> ur.  */
    1846         1676 :           goto do_main;
    1847          531 :         case 2:
    1848              :           /* If s1 is negative, avoid the main code, just multiply and
    1849              :              signal overflow if op1 is not 0.  */
    1850          531 :           struct separate_ops ops;
    1851          531 :           ops.code = MULT_EXPR;
    1852          531 :           ops.type = TREE_TYPE (arg1);
    1853          531 :           ops.op0 = make_tree (ops.type, op0);
    1854          531 :           ops.op1 = make_tree (ops.type, op1);
    1855          531 :           ops.op2 = NULL_TREE;
    1856          531 :           ops.location = loc;
    1857          531 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1858          531 :           do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
    1859              :                                    NULL, done_label, profile_probability::very_likely ());
    1860          727 :           goto do_error_label;
    1861         1872 :         case 3:
    1862         3744 :           if (get_min_precision (arg1, UNSIGNED)
    1863         1872 :               + get_min_precision (arg0, SIGNED) <= GET_MODE_PRECISION (mode))
    1864              :             {
    1865              :               /* If the first operand is sign extended from narrower type, the
    1866              :                  second operand is zero extended from narrower type and
    1867              :                  the sum of the two precisions is smaller or equal to the
    1868              :                  result precision: if the first argument is at runtime
    1869              :                  non-negative, maximum result will be 0x7e81 or 0x7f..fe80..01
    1870              :                  and there will be no overflow, if the first argument is
    1871              :                  negative and the second argument zero, the result will be
    1872              :                  0 and there will be no overflow, if the first argument is
    1873              :                  negative and the second argument positive, the result when
    1874              :                  treated as signed will be negative (minimum -0x7f80 or
    1875              :                  -0x7f..f80..0) there will be always overflow.  So, do
    1876              :                  res = (U) (s1 * u2)
    1877              :                  ovf = (S) res < 0  */
    1878          196 :               struct separate_ops ops;
    1879          196 :               ops.code = MULT_EXPR;
    1880          196 :               ops.type
    1881          196 :                 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    1882              :                                                   1);
    1883          196 :               ops.op0 = make_tree (ops.type, op0);
    1884          196 :               ops.op1 = make_tree (ops.type, op1);
    1885          196 :               ops.op2 = NULL_TREE;
    1886          196 :               ops.location = loc;
    1887          196 :               res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1888          196 :               do_compare_rtx_and_jump (res, const0_rtx, GE, false,
    1889              :                                        mode, NULL_RTX, NULL, done_label,
    1890              :                                        profile_probability::very_likely ());
    1891          196 :               goto do_error_label;
    1892              :             }
    1893         1676 :           rtx_code_label *do_main_label;
    1894         1676 :           do_main_label = gen_label_rtx ();
    1895         1676 :           do_compare_rtx_and_jump (op0, const0_rtx, GE, false, mode, NULL_RTX,
    1896              :                                    NULL, do_main_label, profile_probability::very_likely ());
    1897         1676 :           do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
    1898              :                                    NULL, do_main_label, profile_probability::very_likely ());
    1899         1676 :           expand_arith_set_overflow (lhs, target);
    1900         1676 :           emit_label (do_main_label);
    1901         1676 :           goto do_main;
    1902            0 :         default:
    1903            0 :           gcc_unreachable ();
    1904              :         }
    1905              :     }
    1906              : 
    1907              :   /* u1 * u2 -> sr  */
    1908        16101 :   if (uns0_p && uns1_p && !unsr_p)
    1909              :     {
    1910         1490 :       if ((pos_neg0 | pos_neg1) == 1)
    1911              :         {
    1912              :           /* If both arguments are zero extended from narrower types,
    1913              :              the MSB will be clear on both and so we can pretend it is
    1914              :              a normal s1 * s2 -> sr multiplication.  */
    1915              :           uns0_p = false;
    1916              :           uns1_p = false;
    1917              :         }
    1918              :       else
    1919         1037 :         uns = true;
    1920              :       /* Rest of handling of this case after res is computed.  */
    1921         1490 :       goto do_main;
    1922              :     }
    1923              : 
    1924              :   /* s1 * u2 -> sr  */
    1925        14611 :   if (!uns0_p && uns1_p && !unsr_p)
    1926              :     {
    1927         1553 :       switch (pos_neg1)
    1928              :         {
    1929           48 :         case 1:
    1930         1016 :           goto do_main;
    1931          537 :         case 2:
    1932              :           /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
    1933              :              avoid the main code, just multiply and signal overflow
    1934              :              unless 0 * u2 or -1 * ((U) Smin).  */
    1935          537 :           struct separate_ops ops;
    1936          537 :           ops.code = MULT_EXPR;
    1937          537 :           ops.type = TREE_TYPE (arg1);
    1938          537 :           ops.op0 = make_tree (ops.type, op0);
    1939          537 :           ops.op1 = make_tree (ops.type, op1);
    1940          537 :           ops.op2 = NULL_TREE;
    1941          537 :           ops.location = loc;
    1942          537 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1943          537 :           do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
    1944              :                                    NULL, done_label, profile_probability::very_likely ());
    1945          537 :           do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
    1946              :                                    NULL, do_error, profile_probability::very_unlikely ());
    1947          537 :           int prec;
    1948          537 :           prec = GET_MODE_PRECISION (mode);
    1949          537 :           rtx sgn;
    1950          537 :           sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
    1951          537 :           do_compare_rtx_and_jump (op1, sgn, EQ, true, mode, NULL_RTX,
    1952              :                                    NULL, done_label, profile_probability::very_likely ());
    1953          537 :           goto do_error_label;
    1954          968 :         case 3:
    1955              :           /* Rest of handling of this case after res is computed.  */
    1956          968 :           goto do_main;
    1957            0 :         default:
    1958            0 :           gcc_unreachable ();
    1959              :         }
    1960              :     }
    1961              : 
    1962              :   /* s1 * s2 -> ur  */
    1963        13058 :   if (!uns0_p && !uns1_p && unsr_p)
    1964              :     {
    1965         2078 :       rtx tem;
    1966         2078 :       switch (pos_neg0 | pos_neg1)
    1967              :         {
    1968            0 :         case 1: /* Both operands known to be non-negative.  */
    1969            0 :           goto do_main;
    1970           77 :         case 2: /* Both operands known to be negative.  */
    1971           77 :           op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
    1972           77 :           op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
    1973              :           /* Avoid looking at arg0/arg1 ranges, as we've changed
    1974              :              the arguments.  */
    1975           77 :           arg0 = error_mark_node;
    1976           77 :           arg1 = error_mark_node;
    1977           77 :           goto do_main;
    1978         2001 :         case 3:
    1979         2001 :           if ((pos_neg0 ^ pos_neg1) == 3)
    1980              :             {
    1981              :               /* If one operand is known to be negative and the other
    1982              :                  non-negative, this overflows always, unless the non-negative
    1983              :                  one is 0.  Just do normal multiply and set overflow
    1984              :                  unless one of the operands is 0.  */
    1985            0 :               struct separate_ops ops;
    1986            0 :               ops.code = MULT_EXPR;
    1987            0 :               ops.type
    1988            0 :                 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    1989              :                                                   1);
    1990            0 :               ops.op0 = make_tree (ops.type, op0);
    1991            0 :               ops.op1 = make_tree (ops.type, op1);
    1992            0 :               ops.op2 = NULL_TREE;
    1993            0 :               ops.location = loc;
    1994            0 :               res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    1995            0 :               do_compare_rtx_and_jump (pos_neg0 == 1 ? op0 : op1, const0_rtx, EQ,
    1996              :                                        true, mode, NULL_RTX, NULL, done_label,
    1997              :                                        profile_probability::very_likely ());
    1998            0 :               goto do_error_label;
    1999              :             }
    2000         4002 :           if (get_min_precision (arg0, SIGNED)
    2001         2001 :               + get_min_precision (arg1, SIGNED) <= GET_MODE_PRECISION (mode))
    2002              :             {
    2003              :               /* If both operands are sign extended from narrower types and
    2004              :                  the sum of the two precisions is smaller or equal to the
    2005              :                  result precision: if both arguments are at runtime
    2006              :                  non-negative, maximum result will be 0x3f01 or 0x3f..f0..01
    2007              :                  and there will be no overflow, if both arguments are negative,
    2008              :                  maximum result will be 0x40..00 and there will be no overflow
    2009              :                  either, if one argument is positive and the other argument
    2010              :                  negative, the result when treated as signed will be negative
    2011              :                  and there will be always overflow, and if one argument is
    2012              :                  zero and the other negative the result will be zero and no
    2013              :                  overflow.  So, do
    2014              :                  res = (U) (s1 * s2)
    2015              :                  ovf = (S) res < 0  */
    2016          225 :               struct separate_ops ops;
    2017          225 :               ops.code = MULT_EXPR;
    2018          225 :               ops.type
    2019          225 :                 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
    2020              :                                                   1);
    2021          225 :               ops.op0 = make_tree (ops.type, op0);
    2022          225 :               ops.op1 = make_tree (ops.type, op1);
    2023          225 :               ops.op2 = NULL_TREE;
    2024          225 :               ops.location = loc;
    2025          225 :               res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2026          225 :               do_compare_rtx_and_jump (res, const0_rtx, GE, false,
    2027              :                                        mode, NULL_RTX, NULL, done_label,
    2028              :                                        profile_probability::very_likely ());
    2029          225 :               goto do_error_label;
    2030              :             }
    2031              :           /* The general case, do all the needed comparisons at runtime.  */
    2032         1776 :           rtx_code_label *do_main_label, *after_negate_label;
    2033         1776 :           rtx rop0, rop1;
    2034         1776 :           rop0 = gen_reg_rtx (mode);
    2035         1776 :           rop1 = gen_reg_rtx (mode);
    2036         1776 :           emit_move_insn (rop0, op0);
    2037         1776 :           emit_move_insn (rop1, op1);
    2038         1776 :           op0 = rop0;
    2039         1776 :           op1 = rop1;
    2040         1776 :           do_main_label = gen_label_rtx ();
    2041         1776 :           after_negate_label = gen_label_rtx ();
    2042         1776 :           tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
    2043              :                               OPTAB_LIB_WIDEN);
    2044         1776 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    2045              :                                    NULL, after_negate_label, profile_probability::very_likely ());
    2046              :           /* Both arguments negative here, negate them and continue with
    2047              :              normal unsigned overflow checking multiplication.  */
    2048         1776 :           emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
    2049              :                                             NULL_RTX, false));
    2050         1776 :           emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
    2051              :                                             NULL_RTX, false));
    2052              :           /* Avoid looking at arg0/arg1 ranges, as we might have changed
    2053              :              the arguments.  */
    2054         1776 :           arg0 = error_mark_node;
    2055         1776 :           arg1 = error_mark_node;
    2056         1776 :           emit_jump (do_main_label);
    2057         1776 :           emit_label (after_negate_label);
    2058         1776 :           tem = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
    2059              :                               OPTAB_LIB_WIDEN);
    2060         1776 :           do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
    2061              :                                    NULL, do_main_label,
    2062              :                                    profile_probability::very_likely ());
    2063              :           /* One argument is negative here, the other positive.  This
    2064              :              overflows always, unless one of the arguments is 0.  But
    2065              :              if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
    2066              :              is, thus we can keep do_main code oring in overflow as is.  */
    2067         1776 :           if (pos_neg0 != 2)
    2068         1689 :             do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
    2069              :                                      NULL, do_main_label,
    2070              :                                      profile_probability::very_unlikely ());
    2071         1776 :           if (pos_neg1 != 2)
    2072          699 :             do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
    2073              :                                      NULL, do_main_label,
    2074              :                                      profile_probability::very_unlikely ());
    2075         1776 :           expand_arith_set_overflow (lhs, target);
    2076         1776 :           emit_label (do_main_label);
    2077         1776 :           goto do_main;
    2078            0 :         default:
    2079            0 :           gcc_unreachable ();
    2080              :         }
    2081              :     }
    2082              : 
    2083        10980 :  do_main:
    2084        17015 :   type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
    2085        17015 :   sign = uns ? UNSIGNED : SIGNED;
    2086        17015 :   icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
    2087        17015 :   if (uns
    2088        10150 :       && (integer_pow2p (arg0) || integer_pow2p (arg1))
    2089        17881 :       && (optimize_insn_for_speed_p () || icode == CODE_FOR_nothing))
    2090              :     {
    2091              :       /* Optimize unsigned multiplication by power of 2 constant
    2092              :          using 2 shifts, one for result, one to extract the shifted
    2093              :          out bits to see if they are all zero.
    2094              :          Don't do this if optimizing for size and we have umulv4_optab,
    2095              :          in that case assume multiplication will be shorter.
    2096              :          This is heuristics based on the single target that provides
    2097              :          umulv4 right now (i?86/x86_64), if further targets add it, this
    2098              :          might need to be revisited.
    2099              :          Cases where both operands are constant should be folded already
    2100              :          during GIMPLE, and cases where one operand is constant but not
    2101              :          power of 2 are questionable, either the WIDEN_MULT_EXPR case
    2102              :          below can be done without multiplication, just by shifts and adds,
    2103              :          or we'd need to divide the result (and hope it actually doesn't
    2104              :          really divide nor multiply) and compare the result of the division
    2105              :          with the original operand.  */
    2106          865 :       rtx opn0 = op0;
    2107          865 :       rtx opn1 = op1;
    2108          865 :       tree argn0 = arg0;
    2109          865 :       tree argn1 = arg1;
    2110          865 :       if (integer_pow2p (arg0))
    2111              :         {
    2112            0 :           std::swap (opn0, opn1);
    2113            0 :           std::swap (argn0, argn1);
    2114              :         }
    2115          865 :       int cnt = tree_log2 (argn1);
    2116          865 :       if (cnt >= 0 && cnt < GET_MODE_PRECISION (mode))
    2117              :         {
    2118          865 :           rtx upper = const0_rtx;
    2119          865 :           res = expand_shift (LSHIFT_EXPR, mode, opn0, cnt, NULL_RTX, uns);
    2120          865 :           if (cnt != 0)
    2121          693 :             upper = expand_shift (RSHIFT_EXPR, mode, opn0,
    2122          693 :                                   GET_MODE_PRECISION (mode) - cnt,
    2123              :                                   NULL_RTX, uns);
    2124          865 :           do_compare_rtx_and_jump (upper, const0_rtx, EQ, true, mode,
    2125              :                                    NULL_RTX, NULL, done_label,
    2126              :                                    profile_probability::very_likely ());
    2127          865 :           goto do_error_label;
    2128              :         }
    2129              :     }
    2130        16150 :   if (icode != CODE_FOR_nothing)
    2131              :     {
    2132        13229 :       class expand_operand ops[4];
    2133        13229 :       rtx_insn *last = get_last_insn ();
    2134              : 
    2135        13229 :       res = gen_reg_rtx (mode);
    2136        13229 :       create_output_operand (&ops[0], res, mode);
    2137        13229 :       create_input_operand (&ops[1], op0, mode);
    2138        13229 :       create_input_operand (&ops[2], op1, mode);
    2139        13229 :       create_fixed_operand (&ops[3], do_error);
    2140        13229 :       if (maybe_expand_insn (icode, 4, ops))
    2141              :         {
    2142        13229 :           last = get_last_insn ();
    2143        13229 :           if (profile_status_for_fn (cfun) != PROFILE_ABSENT
    2144         9037 :               && JUMP_P (last)
    2145         9037 :               && any_condjump_p (last)
    2146        22266 :               && !find_reg_note (last, REG_BR_PROB, 0))
    2147         9037 :             add_reg_br_prob_note (last,
    2148              :                                   profile_probability::very_unlikely ());
    2149        13229 :           emit_jump (done_label);
    2150              :         }
    2151              :       else
    2152              :         {
    2153            0 :           delete_insns_since (last);
    2154            0 :           icode = CODE_FOR_nothing;
    2155              :         }
    2156              :     }
    2157              : 
    2158            0 :   if (icode == CODE_FOR_nothing)
    2159              :     {
    2160         2921 :       struct separate_ops ops;
    2161         2921 :       int prec = GET_MODE_PRECISION (mode);
    2162         2921 :       scalar_int_mode hmode, wmode;
    2163         2921 :       ops.op0 = make_tree (type, op0);
    2164         2921 :       ops.op1 = make_tree (type, op1);
    2165         2921 :       ops.op2 = NULL_TREE;
    2166         2921 :       ops.location = loc;
    2167              : 
    2168              :       /* Optimize unsigned overflow check where we don't use the
    2169              :          multiplication result, just whether overflow happened.
    2170              :          If we can do MULT_HIGHPART_EXPR, that followed by
    2171              :          comparison of the result against zero is cheapest.
    2172              :          We'll still compute res, but it should be DCEd later.  */
    2173         2921 :       use_operand_p use;
    2174         2921 :       gimple *use_stmt;
    2175         2921 :       if (!is_ubsan
    2176         2921 :           && lhs
    2177         2901 :           && uns
    2178         1859 :           && !(uns0_p && uns1_p && !unsr_p)
    2179         1574 :           && can_mult_highpart_p (mode, uns) == 1
    2180            0 :           && single_imm_use (lhs, &use, &use_stmt)
    2181            0 :           && is_gimple_assign (use_stmt)
    2182         2921 :           && gimple_assign_rhs_code (use_stmt) == IMAGPART_EXPR)
    2183            0 :         goto highpart;
    2184              : 
    2185         2921 :       if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
    2186         2921 :           && targetm.scalar_mode_supported_p (wmode)
    2187            0 :           && can_widen_mult_without_libcall (wmode, mode, op0, op1, uns))
    2188              :         {
    2189            0 :         twoxwider:
    2190            0 :           ops.code = WIDEN_MULT_EXPR;
    2191            0 :           ops.type
    2192            0 :             = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
    2193              : 
    2194            0 :           res = expand_expr_real_2 (&ops, NULL_RTX, wmode, EXPAND_NORMAL);
    2195            0 :           rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
    2196              :                                      NULL_RTX, uns);
    2197            0 :           hipart = convert_modes (mode, wmode, hipart, uns);
    2198            0 :           res = convert_modes (mode, wmode, res, uns);
    2199            0 :           if (uns)
    2200              :             /* For the unsigned multiplication, there was overflow if
    2201              :                HIPART is non-zero.  */
    2202            0 :             do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
    2203              :                                      NULL_RTX, NULL, done_label,
    2204              :                                      profile_probability::very_likely ());
    2205              :           else
    2206              :             {
    2207              :               /* RES is used more than once, place it in a pseudo.  */
    2208            0 :               res = force_reg (mode, res);
    2209              : 
    2210            0 :               rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
    2211              :                                           NULL_RTX, 0);
    2212              :               /* RES is low half of the double width result, HIPART
    2213              :                  the high half.  There was overflow if
    2214              :                  HIPART is different from RES < 0 ? -1 : 0.  */
    2215            0 :               do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
    2216              :                                        NULL_RTX, NULL, done_label,
    2217              :                                        profile_probability::very_likely ());
    2218              :             }
    2219              :         }
    2220         2921 :       else if (can_mult_highpart_p (mode, uns) == 1)
    2221              :         {
    2222            0 :         highpart:
    2223            0 :           ops.code = MULT_HIGHPART_EXPR;
    2224            0 :           ops.type = type;
    2225              : 
    2226            0 :           rtx hipart = expand_expr_real_2 (&ops, NULL_RTX, mode,
    2227              :                                            EXPAND_NORMAL);
    2228            0 :           ops.code = MULT_EXPR;
    2229            0 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2230            0 :           if (uns)
    2231              :             /* For the unsigned multiplication, there was overflow if
    2232              :                HIPART is non-zero.  */
    2233            0 :             do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
    2234              :                                      NULL_RTX, NULL, done_label,
    2235              :                                      profile_probability::very_likely ());
    2236              :           else
    2237              :             {
    2238            0 :               rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
    2239              :                                           NULL_RTX, 0);
    2240              :               /* RES is low half of the double width result, HIPART
    2241              :                  the high half.  There was overflow if
    2242              :                  HIPART is different from RES < 0 ? -1 : 0.  */
    2243            0 :               do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
    2244              :                                        NULL_RTX, NULL, done_label,
    2245              :                                        profile_probability::very_likely ());
    2246              :             }
    2247              : 
    2248              :         }
    2249         2921 :       else if (int_mode_for_size (prec / 2, 1).exists (&hmode)
    2250         2921 :                && 2 * GET_MODE_PRECISION (hmode) == prec)
    2251              :         {
    2252         2921 :           rtx_code_label *large_op0 = gen_label_rtx ();
    2253         2921 :           rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
    2254         2921 :           rtx_code_label *one_small_one_large = gen_label_rtx ();
    2255         2921 :           rtx_code_label *both_ops_large = gen_label_rtx ();
    2256         2921 :           rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
    2257         1062 :           rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
    2258         2921 :           rtx_code_label *do_overflow = gen_label_rtx ();
    2259         2921 :           rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
    2260              : 
    2261         2921 :           unsigned int hprec = GET_MODE_PRECISION (hmode);
    2262         2921 :           rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
    2263              :                                       NULL_RTX, uns);
    2264         2921 :           hipart0 = convert_modes (hmode, mode, hipart0, uns);
    2265         2921 :           rtx lopart0 = convert_modes (hmode, mode, op0, uns);
    2266         2921 :           rtx signbit0 = const0_rtx;
    2267         2921 :           if (!uns)
    2268         1062 :             signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
    2269              :                                      NULL_RTX, 0);
    2270         2921 :           rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
    2271              :                                       NULL_RTX, uns);
    2272         2921 :           hipart1 = convert_modes (hmode, mode, hipart1, uns);
    2273         2921 :           rtx lopart1 = convert_modes (hmode, mode, op1, uns);
    2274         2921 :           rtx signbit1 = const0_rtx;
    2275         2921 :           if (!uns)
    2276         1062 :             signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
    2277              :                                      NULL_RTX, 0);
    2278              : 
    2279         2921 :           res = gen_reg_rtx (mode);
    2280              : 
    2281              :           /* True if op0 resp. op1 are known to be in the range of
    2282              :              halfstype.  */
    2283         2921 :           bool op0_small_p = false;
    2284         2921 :           bool op1_small_p = false;
    2285              :           /* True if op0 resp. op1 are known to have all zeros or all ones
    2286              :              in the upper half of bits, but are not known to be
    2287              :              op{0,1}_small_p.  */
    2288         2921 :           bool op0_medium_p = false;
    2289         2921 :           bool op1_medium_p = false;
    2290              :           /* -1 if op{0,1} is known to be negative, 0 if it is known to be
    2291              :              nonnegative, 1 if unknown.  */
    2292         2921 :           int op0_sign = 1;
    2293         2921 :           int op1_sign = 1;
    2294              : 
    2295         2921 :           if (pos_neg0 == 1)
    2296              :             op0_sign = 0;
    2297         2595 :           else if (pos_neg0 == 2)
    2298          299 :             op0_sign = -1;
    2299         2921 :           if (pos_neg1 == 1)
    2300              :             op1_sign = 0;
    2301         1634 :           else if (pos_neg1 == 2)
    2302          499 :             op1_sign = -1;
    2303              : 
    2304         2921 :           unsigned int mprec0 = prec;
    2305         2921 :           if (arg0 != error_mark_node)
    2306         2277 :             mprec0 = get_min_precision (arg0, sign);
    2307         2921 :           if (mprec0 <= hprec)
    2308              :             op0_small_p = true;
    2309         2673 :           else if (!uns && mprec0 <= hprec + 1)
    2310         2921 :             op0_medium_p = true;
    2311         2921 :           unsigned int mprec1 = prec;
    2312         2921 :           if (arg1 != error_mark_node)
    2313         2277 :             mprec1 = get_min_precision (arg1, sign);
    2314         2921 :           if (mprec1 <= hprec)
    2315              :             op1_small_p = true;
    2316         2227 :           else if (!uns && mprec1 <= hprec + 1)
    2317         2921 :             op1_medium_p = true;
    2318              : 
    2319         2921 :           int smaller_sign = 1;
    2320         2921 :           int larger_sign = 1;
    2321         2921 :           if (op0_small_p)
    2322              :             {
    2323              :               smaller_sign = op0_sign;
    2324              :               larger_sign = op1_sign;
    2325              :             }
    2326         2673 :           else if (op1_small_p)
    2327              :             {
    2328              :               smaller_sign = op1_sign;
    2329              :               larger_sign = op0_sign;
    2330              :             }
    2331         1979 :           else if (op0_sign == op1_sign)
    2332              :             {
    2333          923 :               smaller_sign = op0_sign;
    2334          923 :               larger_sign = op0_sign;
    2335              :             }
    2336              : 
    2337         2673 :           if (!op0_small_p)
    2338         2673 :             do_compare_rtx_and_jump (signbit0, hipart0, NE, true, hmode,
    2339              :                                      NULL_RTX, NULL, large_op0,
    2340              :                                      profile_probability::unlikely ());
    2341              : 
    2342         2921 :           if (!op1_small_p)
    2343         2227 :             do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
    2344              :                                      NULL_RTX, NULL, small_op0_large_op1,
    2345              :                                      profile_probability::unlikely ());
    2346              : 
    2347              :           /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
    2348              :              hmode to mode, the multiplication will never overflow.  We can
    2349              :              do just one hmode x hmode => mode widening multiplication.  */
    2350         2921 :           tree halfstype = build_nonstandard_integer_type (hprec, uns);
    2351         2921 :           ops.op0 = make_tree (halfstype, lopart0);
    2352         2921 :           ops.op1 = make_tree (halfstype, lopart1);
    2353         2921 :           ops.code = WIDEN_MULT_EXPR;
    2354         2921 :           ops.type = type;
    2355         2921 :           rtx thisres
    2356         2921 :             = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2357         2921 :           emit_move_insn (res, thisres);
    2358         2921 :           emit_jump (done_label);
    2359              : 
    2360         2921 :           emit_label (small_op0_large_op1);
    2361              : 
    2362              :           /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
    2363              :              but op1 is not, just swap the arguments and handle it as op1
    2364              :              sign/zero extended, op0 not.  */
    2365         2921 :           rtx larger = gen_reg_rtx (mode);
    2366         2921 :           rtx hipart = gen_reg_rtx (hmode);
    2367         2921 :           rtx lopart = gen_reg_rtx (hmode);
    2368         2921 :           emit_move_insn (larger, op1);
    2369         2921 :           emit_move_insn (hipart, hipart1);
    2370         2921 :           emit_move_insn (lopart, lopart0);
    2371         2921 :           emit_jump (one_small_one_large);
    2372              : 
    2373         2921 :           emit_label (large_op0);
    2374              : 
    2375         2921 :           if (!op1_small_p)
    2376         2227 :             do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
    2377              :                                      NULL_RTX, NULL, both_ops_large,
    2378              :                                      profile_probability::unlikely ());
    2379              : 
    2380              :           /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
    2381              :              but op0 is not, prepare larger, hipart and lopart pseudos and
    2382              :              handle it together with small_op0_large_op1.  */
    2383         2921 :           emit_move_insn (larger, op0);
    2384         2921 :           emit_move_insn (hipart, hipart0);
    2385         2921 :           emit_move_insn (lopart, lopart1);
    2386              : 
    2387         2921 :           emit_label (one_small_one_large);
    2388              : 
    2389              :           /* lopart is the low part of the operand that is sign extended
    2390              :              to mode, larger is the other operand, hipart is the
    2391              :              high part of larger and lopart0 and lopart1 are the low parts
    2392              :              of both operands.
    2393              :              We perform lopart0 * lopart1 and lopart * hipart widening
    2394              :              multiplications.  */
    2395         2921 :           tree halfutype = build_nonstandard_integer_type (hprec, 1);
    2396         2921 :           ops.op0 = make_tree (halfutype, lopart0);
    2397         2921 :           ops.op1 = make_tree (halfutype, lopart1);
    2398         2921 :           rtx lo0xlo1
    2399         2921 :             = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2400              : 
    2401         2921 :           ops.op0 = make_tree (halfutype, lopart);
    2402         2921 :           ops.op1 = make_tree (halfutype, hipart);
    2403         2921 :           rtx loxhi = gen_reg_rtx (mode);
    2404         2921 :           rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2405         2921 :           emit_move_insn (loxhi, tem);
    2406              : 
    2407         2921 :           if (!uns)
    2408              :             {
    2409              :               /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
    2410         1062 :               if (larger_sign == 0)
    2411          111 :                 emit_jump (after_hipart_neg);
    2412          951 :               else if (larger_sign != -1)
    2413          946 :                 do_compare_rtx_and_jump (hipart, const0_rtx, GE, false, hmode,
    2414              :                                          NULL_RTX, NULL, after_hipart_neg,
    2415              :                                          profile_probability::even ());
    2416              : 
    2417         1062 :               tem = convert_modes (mode, hmode, lopart, 1);
    2418         1062 :               tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
    2419         1062 :               tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
    2420              :                                          1, OPTAB_WIDEN);
    2421         1062 :               emit_move_insn (loxhi, tem);
    2422              : 
    2423         1062 :               emit_label (after_hipart_neg);
    2424              : 
    2425              :               /* if (lopart < 0) loxhi -= larger;  */
    2426         1062 :               if (smaller_sign == 0)
    2427          327 :                 emit_jump (after_lopart_neg);
    2428          735 :               else if (smaller_sign != -1)
    2429          530 :                 do_compare_rtx_and_jump (lopart, const0_rtx, GE, false, hmode,
    2430              :                                          NULL_RTX, NULL, after_lopart_neg,
    2431              :                                          profile_probability::even ());
    2432              : 
    2433         1062 :               tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
    2434              :                                          1, OPTAB_WIDEN);
    2435         1062 :               emit_move_insn (loxhi, tem);
    2436              : 
    2437         1062 :               emit_label (after_lopart_neg);
    2438              :             }
    2439              : 
    2440              :           /* loxhi += (uns) lo0xlo1 >> (bitsize / 2);  */
    2441         2921 :           tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
    2442         2921 :           tem = expand_simple_binop (mode, PLUS, loxhi, tem, NULL_RTX,
    2443              :                                      1, OPTAB_WIDEN);
    2444         2921 :           emit_move_insn (loxhi, tem);
    2445              : 
    2446              :           /* if (loxhi >> (bitsize / 2)
    2447              :                  == (hmode) loxhi >> (bitsize / 2 - 1))  (if !uns)
    2448              :              if (loxhi >> (bitsize / 2) == 0               (if uns).  */
    2449         2921 :           rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
    2450              :                                           NULL_RTX, 0);
    2451         2921 :           hipartloxhi = convert_modes (hmode, mode, hipartloxhi, 0);
    2452         2921 :           rtx signbitloxhi = const0_rtx;
    2453         2921 :           if (!uns)
    2454         1062 :             signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
    2455              :                                          convert_modes (hmode, mode,
    2456              :                                                         loxhi, 0),
    2457         1062 :                                          hprec - 1, NULL_RTX, 0);
    2458              : 
    2459         2921 :           do_compare_rtx_and_jump (signbitloxhi, hipartloxhi, NE, true, hmode,
    2460              :                                    NULL_RTX, NULL, do_overflow,
    2461              :                                    profile_probability::very_unlikely ());
    2462              : 
    2463              :           /* res = (loxhi << (bitsize / 2)) | (hmode) lo0xlo1;  */
    2464         2921 :           rtx loxhishifted = expand_shift (LSHIFT_EXPR, mode, loxhi, hprec,
    2465              :                                            NULL_RTX, 1);
    2466         2921 :           tem = convert_modes (mode, hmode,
    2467              :                                convert_modes (hmode, mode, lo0xlo1, 1), 1);
    2468              : 
    2469         2921 :           tem = expand_simple_binop (mode, IOR, loxhishifted, tem, res,
    2470              :                                      1, OPTAB_WIDEN);
    2471         2921 :           if (tem != res)
    2472            0 :             emit_move_insn (res, tem);
    2473         2921 :           emit_jump (done_label);
    2474              : 
    2475         2921 :           emit_label (both_ops_large);
    2476              : 
    2477              :           /* If both operands are large (not sign (!uns) or zero (uns)
    2478              :              extended from hmode), then perform the full multiplication
    2479              :              which will be the result of the operation.
    2480              :              The only cases which don't overflow are for signed multiplication
    2481              :              some cases where both hipart0 and highpart1 are 0 or -1.
    2482              :              For unsigned multiplication when high parts are both non-zero
    2483              :              this overflows always.  */
    2484         2921 :           ops.code = MULT_EXPR;
    2485         2921 :           ops.op0 = make_tree (type, op0);
    2486         2921 :           ops.op1 = make_tree (type, op1);
    2487         2921 :           tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2488         2921 :           emit_move_insn (res, tem);
    2489              : 
    2490         2921 :           if (!uns)
    2491              :             {
    2492         1062 :               if (!op0_medium_p)
    2493              :                 {
    2494         1062 :                   tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
    2495              :                                              NULL_RTX, 1, OPTAB_WIDEN);
    2496         1062 :                   do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
    2497              :                                            NULL_RTX, NULL, do_error,
    2498              :                                            profile_probability::very_unlikely ());
    2499              :                 }
    2500              : 
    2501         1062 :               if (!op1_medium_p)
    2502              :                 {
    2503         1062 :                   tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
    2504              :                                              NULL_RTX, 1, OPTAB_WIDEN);
    2505         1062 :                   do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
    2506              :                                            NULL_RTX, NULL, do_error,
    2507              :                                            profile_probability::very_unlikely ());
    2508              :                 }
    2509              : 
    2510              :               /* At this point hipart{0,1} are both in [-1, 0].  If they are
    2511              :                  the same, overflow happened if res is non-positive, if they
    2512              :                  are different, overflow happened if res is positive.  */
    2513         1062 :               if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
    2514           23 :                 emit_jump (hipart_different);
    2515         1039 :               else if (op0_sign == 1 || op1_sign == 1)
    2516          937 :                 do_compare_rtx_and_jump (hipart0, hipart1, NE, true, hmode,
    2517              :                                          NULL_RTX, NULL, hipart_different,
    2518              :                                          profile_probability::even ());
    2519              : 
    2520         1062 :               do_compare_rtx_and_jump (res, const0_rtx, LE, false, mode,
    2521              :                                        NULL_RTX, NULL, do_error,
    2522              :                                        profile_probability::very_unlikely ());
    2523         1062 :               emit_jump (done_label);
    2524              : 
    2525         1062 :               emit_label (hipart_different);
    2526              : 
    2527         1062 :               do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode,
    2528              :                                        NULL_RTX, NULL, do_error,
    2529              :                                        profile_probability::very_unlikely ());
    2530         1062 :               emit_jump (done_label);
    2531              :             }
    2532              : 
    2533         2921 :           emit_label (do_overflow);
    2534              : 
    2535              :           /* Overflow, do full multiplication and fallthru into do_error.  */
    2536         2921 :           ops.op0 = make_tree (type, op0);
    2537         2921 :           ops.op1 = make_tree (type, op1);
    2538         2921 :           tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2539         2921 :           emit_move_insn (res, tem);
    2540              :         }
    2541            0 :       else if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
    2542            0 :                && targetm.scalar_mode_supported_p (wmode))
    2543              :         /* Even emitting a libcall is better than not detecting overflow
    2544              :            at all.  */
    2545            0 :         goto twoxwider;
    2546              :       else
    2547              :         {
    2548            0 :           gcc_assert (!is_ubsan);
    2549            0 :           ops.code = MULT_EXPR;
    2550            0 :           ops.type = type;
    2551            0 :           res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2552            0 :           emit_jump (done_label);
    2553              :         }
    2554              :     }
    2555              : 
    2556        13229 :  do_error_label:
    2557        18504 :   emit_label (do_error);
    2558        18504 :   if (is_ubsan)
    2559              :     {
    2560              :       /* Expand the ubsan builtin call.  */
    2561         1506 :       push_temp_slots ();
    2562         1506 :       fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0),
    2563              :                                          arg0, arg1, datap);
    2564         1506 :       expand_normal (fn);
    2565         1506 :       pop_temp_slots ();
    2566         1506 :       do_pending_stack_adjust ();
    2567              :     }
    2568        16998 :   else if (lhs)
    2569        16998 :     expand_arith_set_overflow (lhs, target);
    2570              : 
    2571              :   /* We're done.  */
    2572        18504 :   emit_label (done_label);
    2573              : 
    2574              :   /* u1 * u2 -> sr  */
    2575        18504 :   if (uns0_p && uns1_p && !unsr_p)
    2576              :     {
    2577         1037 :       rtx_code_label *all_done_label = gen_label_rtx ();
    2578         1037 :       do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
    2579              :                                NULL, all_done_label, profile_probability::very_likely ());
    2580         1037 :       expand_arith_set_overflow (lhs, target);
    2581         1037 :       emit_label (all_done_label);
    2582              :     }
    2583              : 
    2584              :   /* s1 * u2 -> sr  */
    2585        18504 :   if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
    2586              :     {
    2587          968 :       rtx_code_label *all_done_label = gen_label_rtx ();
    2588          968 :       rtx_code_label *set_noovf = gen_label_rtx ();
    2589          968 :       do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
    2590              :                                NULL, all_done_label, profile_probability::very_likely ());
    2591          968 :       expand_arith_set_overflow (lhs, target);
    2592          968 :       do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
    2593              :                                NULL, set_noovf, profile_probability::very_likely ());
    2594          968 :       do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
    2595              :                                NULL, all_done_label, profile_probability::very_unlikely ());
    2596          968 :       do_compare_rtx_and_jump (op1, res, NE, true, mode, NULL_RTX, NULL,
    2597              :                                all_done_label, profile_probability::very_unlikely ());
    2598          968 :       emit_label (set_noovf);
    2599          968 :       write_complex_part (target, const0_rtx, true, false);
    2600          968 :       emit_label (all_done_label);
    2601              :     }
    2602              : 
    2603        18504 :   if (lhs)
    2604              :     {
    2605        18360 :       if (is_ubsan)
    2606         1362 :         expand_ubsan_result_store (lhs, target, mode, res, do_error);
    2607              :       else
    2608        16998 :         expand_arith_overflow_result_store (lhs, target, mode, res);
    2609              :     }
    2610        18504 :   flag_trapv = save_flag_trapv;
    2611        18504 : }
    2612              : 
    2613              : /* Expand UBSAN_CHECK_* internal function if it has vector operands.  */
    2614              : 
    2615              : static void
    2616          549 : expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs,
    2617              :                               tree arg0, tree arg1)
    2618              : {
    2619          549 :   poly_uint64 cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
    2620          549 :   rtx_code_label *loop_lab = NULL;
    2621          549 :   rtx cntvar = NULL_RTX;
    2622          549 :   tree cntv = NULL_TREE;
    2623          549 :   tree eltype = TREE_TYPE (TREE_TYPE (arg0));
    2624          549 :   tree sz = TYPE_SIZE (eltype);
    2625          549 :   tree data = NULL_TREE;
    2626          549 :   tree resv = NULL_TREE;
    2627          549 :   rtx lhsr = NULL_RTX;
    2628          549 :   rtx resvr = NULL_RTX;
    2629          549 :   unsigned HOST_WIDE_INT const_cnt = 0;
    2630          549 :   bool use_loop_p = (!cnt.is_constant (&const_cnt) || const_cnt > 4);
    2631          549 :   int save_flag_trapv = flag_trapv;
    2632              : 
    2633              :   /* We don't want any __mulv?i3 etc. calls from the expansion of
    2634              :      these internal functions, so disable -ftrapv temporarily.  */
    2635          549 :   flag_trapv = 0;
    2636          549 :   if (lhs)
    2637              :     {
    2638          549 :       optab op;
    2639          549 :       lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    2640          141 :       if (!VECTOR_MODE_P (GET_MODE (lhsr))
    2641          408 :           || (op = optab_for_tree_code (code, TREE_TYPE (arg0),
    2642              :                                         optab_default)) == unknown_optab
    2643          957 :           || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0)))
    2644              :               == CODE_FOR_nothing))
    2645              :         {
    2646          141 :           if (MEM_P (lhsr))
    2647          141 :             resv = make_tree (TREE_TYPE (lhs), lhsr);
    2648              :           else
    2649              :             {
    2650            0 :               resvr = assign_temp (TREE_TYPE (lhs), 1, 1);
    2651            0 :               resv = make_tree (TREE_TYPE (lhs), resvr);
    2652              :             }
    2653              :         }
    2654              :     }
    2655          549 :   if (use_loop_p)
    2656              :     {
    2657          417 :       do_pending_stack_adjust ();
    2658          417 :       loop_lab = gen_label_rtx ();
    2659          417 :       cntvar = gen_reg_rtx (TYPE_MODE (sizetype));
    2660          417 :       cntv = make_tree (sizetype, cntvar);
    2661          417 :       emit_move_insn (cntvar, const0_rtx);
    2662          417 :       emit_label (loop_lab);
    2663              :     }
    2664          549 :   if (TREE_CODE (arg0) != VECTOR_CST)
    2665              :     {
    2666          461 :       rtx arg0r = expand_normal (arg0);
    2667          461 :       arg0 = make_tree (TREE_TYPE (arg0), arg0r);
    2668              :     }
    2669          549 :   if (TREE_CODE (arg1) != VECTOR_CST)
    2670              :     {
    2671          537 :       rtx arg1r = expand_normal (arg1);
    2672          537 :       arg1 = make_tree (TREE_TYPE (arg1), arg1r);
    2673              :     }
    2674         2154 :   for (unsigned int i = 0; i < (use_loop_p ? 1 : const_cnt); i++)
    2675              :     {
    2676          945 :       tree op0, op1, res = NULL_TREE;
    2677          945 :       if (use_loop_p)
    2678              :         {
    2679          417 :           tree atype = build_array_type_nelts (eltype, cnt);
    2680          417 :           op0 = uniform_vector_p (arg0);
    2681          417 :           if (op0 == NULL_TREE)
    2682              :             {
    2683          351 :               op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0);
    2684          351 :               op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv,
    2685              :                                 NULL_TREE, NULL_TREE);
    2686              :             }
    2687          417 :           op1 = uniform_vector_p (arg1);
    2688          417 :           if (op1 == NULL_TREE)
    2689              :             {
    2690          411 :               op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1);
    2691          411 :               op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv,
    2692              :                                 NULL_TREE, NULL_TREE);
    2693              :             }
    2694          417 :           if (resv)
    2695              :             {
    2696          141 :               res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv);
    2697          141 :               res = build4_loc (loc, ARRAY_REF, eltype, res, cntv,
    2698              :                                 NULL_TREE, NULL_TREE);
    2699              :             }
    2700              :         }
    2701              :       else
    2702              :         {
    2703          528 :           tree bitpos = bitsize_int (tree_to_uhwi (sz) * i);
    2704          528 :           op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos);
    2705          528 :           op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos);
    2706          528 :           if (resv)
    2707            0 :             res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz,
    2708              :                                    bitpos);
    2709              :         }
    2710          945 :       switch (code)
    2711              :         {
    2712          317 :         case PLUS_EXPR:
    2713          317 :           expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1,
    2714              :                                   false, false, false, true, &data);
    2715          317 :           break;
    2716          462 :         case MINUS_EXPR:
    2717          462 :           if (use_loop_p ? integer_zerop (arg0) : integer_zerop (op0))
    2718          154 :             expand_neg_overflow (loc, res, op1, true, &data);
    2719              :           else
    2720          308 :             expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1,
    2721              :                                     false, false, false, true, &data);
    2722              :           break;
    2723          166 :         case MULT_EXPR:
    2724          166 :           expand_mul_overflow (loc, res, op0, op1, false, false, false,
    2725              :                                true, &data);
    2726          166 :           break;
    2727            0 :         default:
    2728            0 :           gcc_unreachable ();
    2729              :         }
    2730              :     }
    2731          549 :   if (use_loop_p)
    2732              :     {
    2733          417 :       struct separate_ops ops;
    2734          417 :       ops.code = PLUS_EXPR;
    2735          417 :       ops.type = TREE_TYPE (cntv);
    2736          417 :       ops.op0 = cntv;
    2737          417 :       ops.op1 = build_int_cst (TREE_TYPE (cntv), 1);
    2738          417 :       ops.op2 = NULL_TREE;
    2739          417 :       ops.location = loc;
    2740          417 :       rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype),
    2741              :                                     EXPAND_NORMAL);
    2742          417 :       if (ret != cntvar)
    2743            0 :         emit_move_insn (cntvar, ret);
    2744          417 :       rtx cntrtx = gen_int_mode (cnt, TYPE_MODE (sizetype));
    2745          834 :       do_compare_rtx_and_jump (cntvar, cntrtx, NE, false,
    2746          417 :                                TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab,
    2747              :                                profile_probability::very_likely ());
    2748              :     }
    2749          549 :   if (lhs && resv == NULL_TREE)
    2750              :     {
    2751          408 :       struct separate_ops ops;
    2752          408 :       ops.code = code;
    2753          408 :       ops.type = TREE_TYPE (arg0);
    2754          408 :       ops.op0 = arg0;
    2755          408 :       ops.op1 = arg1;
    2756          408 :       ops.op2 = NULL_TREE;
    2757          408 :       ops.location = loc;
    2758          408 :       rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)),
    2759              :                                     EXPAND_NORMAL);
    2760          408 :       if (ret != lhsr)
    2761            5 :         emit_move_insn (lhsr, ret);
    2762              :     }
    2763          141 :   else if (resvr)
    2764            0 :     emit_move_insn (lhsr, resvr);
    2765          549 :   flag_trapv = save_flag_trapv;
    2766          549 : }
    2767              : 
    2768              : /* Expand UBSAN_CHECK_ADD call STMT.  */
    2769              : 
    2770              : static void
    2771         1787 : expand_UBSAN_CHECK_ADD (internal_fn, gcall *stmt)
    2772              : {
    2773         1787 :   location_t loc = gimple_location (stmt);
    2774         1787 :   tree lhs = gimple_call_lhs (stmt);
    2775         1787 :   tree arg0 = gimple_call_arg (stmt, 0);
    2776         1787 :   tree arg1 = gimple_call_arg (stmt, 1);
    2777         1787 :   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
    2778          185 :     expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1);
    2779              :   else
    2780         1602 :     expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
    2781              :                             false, false, false, true, NULL);
    2782         1787 : }
    2783              : 
    2784              : /* Expand UBSAN_CHECK_SUB call STMT.  */
    2785              : 
    2786              : static void
    2787         1840 : expand_UBSAN_CHECK_SUB (internal_fn, gcall *stmt)
    2788              : {
    2789         1840 :   location_t loc = gimple_location (stmt);
    2790         1840 :   tree lhs = gimple_call_lhs (stmt);
    2791         1840 :   tree arg0 = gimple_call_arg (stmt, 0);
    2792         1840 :   tree arg1 = gimple_call_arg (stmt, 1);
    2793         1840 :   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
    2794          264 :     expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1);
    2795         1576 :   else if (integer_zerop (arg0))
    2796          417 :     expand_neg_overflow (loc, lhs, arg1, true, NULL);
    2797              :   else
    2798         1159 :     expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
    2799              :                             false, false, false, true, NULL);
    2800         1840 : }
    2801              : 
    2802              : /* Expand UBSAN_CHECK_MUL call STMT.  */
    2803              : 
    2804              : static void
    2805         1440 : expand_UBSAN_CHECK_MUL (internal_fn, gcall *stmt)
    2806              : {
    2807         1440 :   location_t loc = gimple_location (stmt);
    2808         1440 :   tree lhs = gimple_call_lhs (stmt);
    2809         1440 :   tree arg0 = gimple_call_arg (stmt, 0);
    2810         1440 :   tree arg1 = gimple_call_arg (stmt, 1);
    2811         1440 :   if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
    2812          100 :     expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1);
    2813              :   else
    2814         1340 :     expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true,
    2815              :                          NULL);
    2816         1440 : }
    2817              : 
    2818              : /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion.  */
    2819              : 
    2820              : static void
    2821        71711 : expand_arith_overflow (enum tree_code code, gimple *stmt)
    2822              : {
    2823        71711 :   tree lhs = gimple_call_lhs (stmt);
    2824        71711 :   if (lhs == NULL_TREE)
    2825              :     return;
    2826        71711 :   tree arg0 = gimple_call_arg (stmt, 0);
    2827        71711 :   tree arg1 = gimple_call_arg (stmt, 1);
    2828        71711 :   tree type = TREE_TYPE (TREE_TYPE (lhs));
    2829        71711 :   int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
    2830        71711 :   int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
    2831        71711 :   int unsr_p = TYPE_UNSIGNED (type);
    2832        71711 :   int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
    2833        71711 :   int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
    2834        71711 :   int precres = TYPE_PRECISION (type);
    2835        71711 :   location_t loc = gimple_location (stmt);
    2836        71711 :   if (!uns0_p && get_range_pos_neg (arg0, stmt) == 1)
    2837              :     uns0_p = true;
    2838        71711 :   if (!uns1_p && get_range_pos_neg (arg1, stmt) == 1)
    2839              :     uns1_p = true;
    2840       103428 :   int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
    2841        71711 :   prec0 = MIN (prec0, pr);
    2842        94737 :   pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
    2843        71711 :   prec1 = MIN (prec1, pr);
    2844        71711 :   int save_flag_trapv = flag_trapv;
    2845              : 
    2846              :   /* We don't want any __mulv?i3 etc. calls from the expansion of
    2847              :      these internal functions, so disable -ftrapv temporarily.  */
    2848        71711 :   flag_trapv = 0;
    2849              :   /* If uns0_p && uns1_p, precop is minimum needed precision
    2850              :      of unsigned type to hold the exact result, otherwise
    2851              :      precop is minimum needed precision of signed type to
    2852              :      hold the exact result.  */
    2853        71711 :   int precop;
    2854        71711 :   if (code == MULT_EXPR)
    2855        23231 :     precop = prec0 + prec1 + (uns0_p != uns1_p);
    2856              :   else
    2857              :     {
    2858        48480 :       if (uns0_p == uns1_p)
    2859        31143 :         precop = MAX (prec0, prec1) + 1;
    2860        17337 :       else if (uns0_p)
    2861         6123 :         precop = MAX (prec0 + 1, prec1) + 1;
    2862              :       else
    2863        11214 :         precop = MAX (prec0, prec1 + 1) + 1;
    2864              :     }
    2865        71711 :   int orig_precres = precres;
    2866              : 
    2867        90257 :   do
    2868              :     {
    2869        90257 :       if ((uns0_p && uns1_p)
    2870        90257 :           ? ((precop + !unsr_p) <= precres
    2871              :              /* u1 - u2 -> ur can overflow, no matter what precision
    2872              :                 the result has.  */
    2873        35631 :              && (code != MINUS_EXPR || !unsr_p))
    2874        54626 :           : (!unsr_p && precop <= precres))
    2875              :         {
    2876              :           /* The infinity precision result will always fit into result.  */
    2877        18301 :           rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    2878        18301 :           write_complex_part (target, const0_rtx, true, false);
    2879        18301 :           scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
    2880        18301 :           struct separate_ops ops;
    2881        18301 :           ops.code = code;
    2882        18301 :           ops.type = type;
    2883        18301 :           ops.op0 = fold_convert_loc (loc, type, arg0);
    2884        18301 :           ops.op1 = fold_convert_loc (loc, type, arg1);
    2885        18301 :           ops.op2 = NULL_TREE;
    2886        18301 :           ops.location = loc;
    2887        18301 :           rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    2888        18301 :           expand_arith_overflow_result_store (lhs, target, mode, tem);
    2889        18301 :           flag_trapv = save_flag_trapv;
    2890        18301 :           return;
    2891              :         }
    2892              : 
    2893              :       /* For operations with low precision, if target doesn't have them, start
    2894              :          with precres widening right away, otherwise do it only if the most
    2895              :          simple cases can't be used.  */
    2896        71956 :       const int min_precision = targetm.min_arithmetic_precision ();
    2897        71956 :       if (orig_precres == precres && precres < min_precision)
    2898              :         ;
    2899        70693 :       else if ((uns0_p && uns1_p && unsr_p && prec0 <= precres
    2900        21427 :                 && prec1 <= precres)
    2901        49269 :           || ((!uns0_p || !uns1_p) && !unsr_p
    2902        19221 :               && prec0 + uns0_p <= precres
    2903        16440 :               && prec1 + uns1_p <= precres))
    2904              :         {
    2905        34378 :           arg0 = fold_convert_loc (loc, type, arg0);
    2906        34378 :           arg1 = fold_convert_loc (loc, type, arg1);
    2907        34378 :           switch (code)
    2908              :             {
    2909        10179 :             case MINUS_EXPR:
    2910        10179 :               if (integer_zerop (arg0) && !unsr_p)
    2911              :                 {
    2912          402 :                   expand_neg_overflow (loc, lhs, arg1, false, NULL);
    2913          402 :                   flag_trapv = save_flag_trapv;
    2914          402 :                   return;
    2915              :                 }
    2916              :               /* FALLTHRU */
    2917        24502 :             case PLUS_EXPR:
    2918        24502 :               expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
    2919              :                                       unsr_p, unsr_p, false, NULL);
    2920        24502 :               flag_trapv = save_flag_trapv;
    2921        24502 :               return;
    2922         9474 :             case MULT_EXPR:
    2923         9474 :               expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
    2924              :                                    unsr_p, unsr_p, false, NULL);
    2925         9474 :               flag_trapv = save_flag_trapv;
    2926         9474 :               return;
    2927            0 :             default:
    2928            0 :               gcc_unreachable ();
    2929              :             }
    2930              :         }
    2931              : 
    2932              :       /* For sub-word operations, retry with a wider type first.  */
    2933        37579 :       if (orig_precres == precres && precop <= BITS_PER_WORD)
    2934              :         {
    2935        19641 :           int p = MAX (min_precision, precop);
    2936        19641 :           scalar_int_mode m = smallest_int_mode_for_size (p).require ();
    2937        19641 :           tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
    2938              :                                                         uns0_p && uns1_p
    2939        19641 :                                                         && unsr_p);
    2940        19641 :           p = TYPE_PRECISION (optype);
    2941        19641 :           if (p > precres)
    2942              :             {
    2943        17988 :               precres = p;
    2944        17988 :               unsr_p = TYPE_UNSIGNED (optype);
    2945        17988 :               type = optype;
    2946        17988 :               continue;
    2947              :             }
    2948              :         }
    2949              : 
    2950        19590 :       if (prec0 <= precres && prec1 <= precres)
    2951              :         {
    2952        19032 :           tree types[2];
    2953        19032 :           if (unsr_p)
    2954              :             {
    2955        10937 :               types[0] = build_nonstandard_integer_type (precres, 0);
    2956        10937 :               types[1] = type;
    2957              :             }
    2958              :           else
    2959              :             {
    2960         8095 :               types[0] = type;
    2961         8095 :               types[1] = build_nonstandard_integer_type (precres, 1);
    2962              :             }
    2963        19032 :           arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
    2964        19032 :           arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
    2965        19032 :           if (code != MULT_EXPR)
    2966        11508 :             expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
    2967              :                                     uns0_p, uns1_p, false, NULL);
    2968              :           else
    2969         7524 :             expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
    2970              :                                  uns0_p, uns1_p, false, NULL);
    2971        19032 :           flag_trapv = save_flag_trapv;
    2972        19032 :           return;
    2973              :         }
    2974              : 
    2975              :       /* Retry with a wider type.  */
    2976          558 :       if (orig_precres == precres)
    2977              :         {
    2978          558 :           int p = MAX (prec0, prec1);
    2979          558 :           scalar_int_mode m = smallest_int_mode_for_size (p).require ();
    2980          558 :           tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
    2981              :                                                         uns0_p && uns1_p
    2982          558 :                                                         && unsr_p);
    2983          558 :           p = TYPE_PRECISION (optype);
    2984          558 :           if (p > precres)
    2985              :             {
    2986          558 :               precres = p;
    2987          558 :               unsr_p = TYPE_UNSIGNED (optype);
    2988          558 :               type = optype;
    2989          558 :               continue;
    2990              :             }
    2991              :         }
    2992              : 
    2993            0 :       gcc_unreachable ();
    2994              :     }
    2995              :   while (1);
    2996              : }
    2997              : 
    2998              : /* Expand ADD_OVERFLOW STMT.  */
    2999              : 
    3000              : static void
    3001        25036 : expand_ADD_OVERFLOW (internal_fn, gcall *stmt)
    3002              : {
    3003        25036 :   expand_arith_overflow (PLUS_EXPR, stmt);
    3004        25036 : }
    3005              : 
    3006              : /* Expand SUB_OVERFLOW STMT.  */
    3007              : 
    3008              : static void
    3009        23444 : expand_SUB_OVERFLOW (internal_fn, gcall *stmt)
    3010              : {
    3011        23444 :   expand_arith_overflow (MINUS_EXPR, stmt);
    3012        23444 : }
    3013              : 
    3014              : /* Expand MUL_OVERFLOW STMT.  */
    3015              : 
    3016              : static void
    3017        23231 : expand_MUL_OVERFLOW (internal_fn, gcall *stmt)
    3018              : {
    3019        23231 :   expand_arith_overflow (MULT_EXPR, stmt);
    3020        23231 : }
    3021              : 
    3022              : /* Expand UADDC STMT.  */
    3023              : 
    3024              : static void
    3025        15132 : expand_UADDC (internal_fn ifn, gcall *stmt)
    3026              : {
    3027        15132 :   tree lhs = gimple_call_lhs (stmt);
    3028        15132 :   tree arg1 = gimple_call_arg (stmt, 0);
    3029        15132 :   tree arg2 = gimple_call_arg (stmt, 1);
    3030        15132 :   tree arg3 = gimple_call_arg (stmt, 2);
    3031        15132 :   tree type = TREE_TYPE (arg1);
    3032        15132 :   machine_mode mode = TYPE_MODE (type);
    3033        21253 :   insn_code icode = optab_handler (ifn == IFN_UADDC
    3034              :                                    ? uaddc5_optab : usubc5_optab, mode);
    3035        15132 :   rtx op1 = expand_normal (arg1);
    3036        15132 :   rtx op2 = expand_normal (arg2);
    3037        15132 :   rtx op3 = expand_normal (arg3);
    3038        15132 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3039        15132 :   rtx re = gen_reg_rtx (mode);
    3040        15132 :   rtx im = gen_reg_rtx (mode);
    3041        15132 :   class expand_operand ops[5];
    3042        15132 :   create_output_operand (&ops[0], re, mode);
    3043        15132 :   create_output_operand (&ops[1], im, mode);
    3044        15132 :   create_input_operand (&ops[2], op1, mode);
    3045        15132 :   create_input_operand (&ops[3], op2, mode);
    3046        15132 :   create_input_operand (&ops[4], op3, mode);
    3047        15132 :   expand_insn (icode, 5, ops);
    3048        15132 :   write_complex_part (target, re, false, false);
    3049        15132 :   write_complex_part (target, im, true, false);
    3050        15132 : }
    3051              : 
    3052              : /* Expand USUBC STMT.  */
    3053              : 
    3054              : static void
    3055         6121 : expand_USUBC (internal_fn ifn, gcall *stmt)
    3056              : {
    3057         6121 :   expand_UADDC (ifn, stmt);
    3058         6121 : }
    3059              : 
    3060              : /* This should get folded in tree-vectorizer.cc.  */
    3061              : 
    3062              : static void
    3063            0 : expand_LOOP_VECTORIZED (internal_fn, gcall *)
    3064              : {
    3065            0 :   gcc_unreachable ();
    3066              : }
    3067              : 
    3068              : /* This should get folded in tree-vectorizer.cc.  */
    3069              : 
    3070              : static void
    3071            0 : expand_LOOP_DIST_ALIAS (internal_fn, gcall *)
    3072              : {
    3073            0 :   gcc_unreachable ();
    3074              : }
    3075              : 
    3076              : /* Return a memory reference of type TYPE for argument INDEX of STMT.
    3077              :    Use argument INDEX + 1 to derive the second (TBAA) operand.  */
    3078              : 
    3079              : static tree
    3080         1479 : expand_call_mem_ref (tree type, gcall *stmt, int index)
    3081              : {
    3082         1479 :   tree addr = gimple_call_arg (stmt, index);
    3083         1479 :   tree alias_ptr_type = TREE_TYPE (gimple_call_arg (stmt, index + 1));
    3084         1479 :   unsigned int align = tree_to_shwi (gimple_call_arg (stmt, index + 1));
    3085         1479 :   if (TYPE_ALIGN (type) != align)
    3086         1213 :     type = build_aligned_type (type, align);
    3087              : 
    3088         1479 :   tree tmp = addr;
    3089         1479 :   if (TREE_CODE (tmp) == SSA_NAME)
    3090              :     {
    3091         1349 :       gimple *def = get_gimple_for_ssa_name (tmp);
    3092         1349 :       if (def && gimple_assign_single_p (def))
    3093          598 :         tmp = gimple_assign_rhs1 (def);
    3094              :     }
    3095              : 
    3096         1479 :   if (TREE_CODE (tmp) == ADDR_EXPR)
    3097              :     {
    3098          728 :       tree mem = TREE_OPERAND (tmp, 0);
    3099          728 :       if (TREE_CODE (mem) == TARGET_MEM_REF
    3100          728 :           && types_compatible_p (TREE_TYPE (mem), type))
    3101              :         {
    3102          598 :           tree offset = TMR_OFFSET (mem);
    3103          598 :           if (type != TREE_TYPE (mem)
    3104          144 :               || alias_ptr_type != TREE_TYPE (offset)
    3105          742 :               || !integer_zerop (offset))
    3106              :             {
    3107          481 :               mem = copy_node (mem);
    3108          962 :               TMR_OFFSET (mem) = wide_int_to_tree (alias_ptr_type,
    3109          481 :                                                    wi::to_poly_wide (offset));
    3110          481 :               TREE_TYPE (mem) = type;
    3111              :             }
    3112          598 :           return mem;
    3113              :         }
    3114              :     }
    3115              : 
    3116          881 :   return fold_build2 (MEM_REF, type, addr, build_int_cst (alias_ptr_type, 0));
    3117              : }
    3118              : 
    3119              : /* Expand MASK_LOAD{,_LANES}, MASK_LEN_LOAD or LEN_LOAD call STMT using optab
    3120              :  * OPTAB.  */
    3121              : 
    3122              : static void
    3123          721 : expand_partial_load_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
    3124              : {
    3125          721 :   int i = 0;
    3126          721 :   class expand_operand ops[6];
    3127          721 :   tree type, lhs, rhs, maskt;
    3128          721 :   rtx mem, target;
    3129          721 :   insn_code icode;
    3130              : 
    3131          721 :   maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
    3132          721 :   lhs = gimple_call_lhs (stmt);
    3133          721 :   if (lhs == NULL_TREE)
    3134            0 :     return;
    3135          721 :   type = TREE_TYPE (lhs);
    3136          721 :   rhs = expand_call_mem_ref (type, stmt, 0);
    3137              : 
    3138          721 :   if (optab == vec_mask_load_lanes_optab
    3139          721 :       || optab == vec_mask_len_load_lanes_optab)
    3140            0 :     icode = get_multi_vector_move (type, optab);
    3141          721 :   else if (optab == len_load_optab)
    3142            0 :     icode = direct_optab_handler (optab, TYPE_MODE (type));
    3143              :   else
    3144          721 :     icode = convert_optab_handler (optab, TYPE_MODE (type),
    3145          721 :                                    TYPE_MODE (TREE_TYPE (maskt)));
    3146              : 
    3147          721 :   mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3148          721 :   gcc_assert (MEM_P (mem));
    3149              :   /* The built MEM_REF does not accurately reflect that the load
    3150              :      is only partial.  Clear it.  */
    3151          721 :   set_mem_expr (mem, NULL_TREE);
    3152          721 :   clear_mem_offset (mem);
    3153          721 :   target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3154          721 :   create_call_lhs_operand (&ops[i++], target, TYPE_MODE (type));
    3155          721 :   create_fixed_operand (&ops[i++], mem);
    3156          721 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3157          721 :   expand_insn (icode, i, ops);
    3158              : 
    3159          721 :   assign_call_lhs (lhs, target, &ops[0]);
    3160              : }
    3161              : 
    3162              : #define expand_mask_load_optab_fn expand_partial_load_optab_fn
    3163              : #define expand_mask_load_lanes_optab_fn expand_mask_load_optab_fn
    3164              : #define expand_len_load_optab_fn expand_partial_load_optab_fn
    3165              : #define expand_mask_len_load_optab_fn expand_partial_load_optab_fn
    3166              : 
    3167              : /* Expand MASK_STORE{,_LANES}, MASK_LEN_STORE or LEN_STORE call STMT using optab
    3168              :  * OPTAB.  */
    3169              : 
    3170              : static void
    3171          758 : expand_partial_store_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
    3172              : {
    3173          758 :   int i = 0;
    3174          758 :   class expand_operand ops[5];
    3175          758 :   tree type, lhs, rhs, maskt;
    3176          758 :   rtx mem, reg;
    3177          758 :   insn_code icode;
    3178              : 
    3179          758 :   maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
    3180          758 :   rhs = gimple_call_arg (stmt, internal_fn_stored_value_index (ifn));
    3181          758 :   type = TREE_TYPE (rhs);
    3182          758 :   lhs = expand_call_mem_ref (type, stmt, 0);
    3183              : 
    3184          758 :   if (optab == vec_mask_store_lanes_optab
    3185          758 :       || optab == vec_mask_len_store_lanes_optab)
    3186            0 :     icode = get_multi_vector_move (type, optab);
    3187          758 :   else if (optab == len_store_optab)
    3188            0 :     icode = direct_optab_handler (optab, TYPE_MODE (type));
    3189              :   else
    3190          758 :     icode = convert_optab_handler (optab, TYPE_MODE (type),
    3191          758 :                                    TYPE_MODE (TREE_TYPE (maskt)));
    3192              : 
    3193          758 :   mem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3194          758 :   gcc_assert (MEM_P (mem));
    3195              :   /* The built MEM_REF does not accurately reflect that the store
    3196              :      is only partial.  Clear it.  */
    3197          758 :   set_mem_expr (mem, NULL_TREE);
    3198          758 :   clear_mem_offset (mem);
    3199          758 :   reg = expand_normal (rhs);
    3200          758 :   create_fixed_operand (&ops[i++], mem);
    3201          758 :   create_input_operand (&ops[i++], reg, TYPE_MODE (type));
    3202          758 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3203          758 :   expand_insn (icode, i, ops);
    3204          758 : }
    3205              : 
    3206              : #define expand_mask_store_optab_fn expand_partial_store_optab_fn
    3207              : #define expand_mask_store_lanes_optab_fn expand_mask_store_optab_fn
    3208              : #define expand_len_store_optab_fn expand_partial_store_optab_fn
    3209              : #define expand_mask_len_store_optab_fn expand_partial_store_optab_fn
    3210              : 
    3211              : /* Expand VCOND_MASK optab internal function.
    3212              :    The expansion of STMT happens based on OPTAB table associated.  */
    3213              : 
    3214              : static void
    3215         8850 : expand_vec_cond_mask_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
    3216              : {
    3217         8850 :   class expand_operand ops[4];
    3218              : 
    3219         8850 :   tree lhs = gimple_call_lhs (stmt);
    3220         8850 :   tree op0 = gimple_call_arg (stmt, 0);
    3221         8850 :   tree op1 = gimple_call_arg (stmt, 1);
    3222         8850 :   tree op2 = gimple_call_arg (stmt, 2);
    3223         8850 :   tree vec_cond_type = TREE_TYPE (lhs);
    3224              : 
    3225         8850 :   machine_mode mode = TYPE_MODE (vec_cond_type);
    3226         8850 :   machine_mode mask_mode = TYPE_MODE (TREE_TYPE (op0));
    3227         8850 :   enum insn_code icode = convert_optab_handler (optab, mode, mask_mode);
    3228         8850 :   rtx mask, rtx_op1, rtx_op2;
    3229              : 
    3230         8850 :   gcc_assert (icode != CODE_FOR_nothing);
    3231              : 
    3232         8850 :   mask = expand_normal (op0);
    3233         8850 :   rtx_op1 = expand_normal (op1);
    3234         8850 :   rtx_op2 = expand_normal (op2);
    3235              : 
    3236         8850 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3237         8850 :   create_call_lhs_operand (&ops[0], target, mode);
    3238         8850 :   create_input_operand (&ops[1], rtx_op1, mode);
    3239         8850 :   create_input_operand (&ops[2], rtx_op2, mode);
    3240         8850 :   create_input_operand (&ops[3], mask, mask_mode);
    3241         8850 :   expand_insn (icode, 4, ops);
    3242         8850 :   assign_call_lhs (lhs, target, &ops[0]);
    3243         8850 : }
    3244              : 
    3245              : /* Expand VEC_SET internal functions.  */
    3246              : 
    3247              : static void
    3248          123 : expand_vec_set_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
    3249              : {
    3250          123 :   tree lhs = gimple_call_lhs (stmt);
    3251          123 :   tree op0 = gimple_call_arg (stmt, 0);
    3252          123 :   tree op1 = gimple_call_arg (stmt, 1);
    3253          123 :   tree op2 = gimple_call_arg (stmt, 2);
    3254          123 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3255          123 :   rtx src = expand_normal (op0);
    3256              : 
    3257          123 :   machine_mode outermode = TYPE_MODE (TREE_TYPE (op0));
    3258          123 :   scalar_mode innermode = GET_MODE_INNER (outermode);
    3259              : 
    3260          123 :   rtx value = expand_normal (op1);
    3261          123 :   rtx pos = expand_normal (op2);
    3262              : 
    3263          123 :   class expand_operand ops[3];
    3264          123 :   enum insn_code icode = optab_handler (optab, outermode);
    3265              : 
    3266          123 :   if (icode != CODE_FOR_nothing)
    3267              :     {
    3268          123 :       rtx temp = gen_reg_rtx (outermode);
    3269          123 :       emit_move_insn (temp, src);
    3270              : 
    3271          123 :       create_fixed_operand (&ops[0], temp);
    3272          123 :       create_input_operand (&ops[1], value, innermode);
    3273          123 :       create_convert_operand_from (&ops[2], pos, TYPE_MODE (TREE_TYPE (op2)),
    3274              :                                    true);
    3275          123 :       if (maybe_expand_insn (icode, 3, ops))
    3276              :         {
    3277          123 :           emit_move_insn (target, temp);
    3278          123 :           return;
    3279              :         }
    3280              :     }
    3281            0 :   gcc_unreachable ();
    3282              : }
    3283              : 
    3284              : static void
    3285         1828 : expand_ABNORMAL_DISPATCHER (internal_fn, gcall *)
    3286              : {
    3287         1828 : }
    3288              : 
    3289              : static void
    3290            0 : expand_BUILTIN_EXPECT (internal_fn, gcall *stmt)
    3291              : {
    3292              :   /* When guessing was done, the hints should be already stripped away.  */
    3293            0 :   gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ());
    3294              : 
    3295            0 :   rtx target;
    3296            0 :   tree lhs = gimple_call_lhs (stmt);
    3297            0 :   if (lhs)
    3298            0 :     target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3299              :   else
    3300            0 :     target = const0_rtx;
    3301            0 :   rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL);
    3302            0 :   if (lhs && val != target)
    3303            0 :     emit_move_insn (target, val);
    3304            0 : }
    3305              : 
    3306              : /* IFN_VA_ARG is supposed to be expanded at pass_stdarg.  So this dummy function
    3307              :    should never be called.  */
    3308              : 
    3309              : static void
    3310            0 : expand_VA_ARG (internal_fn, gcall *)
    3311              : {
    3312            0 :   gcc_unreachable ();
    3313              : }
    3314              : 
    3315              : /* IFN_VEC_CONVERT is supposed to be expanded at pass_lower_vector.  So this
    3316              :    dummy function should never be called.  */
    3317              : 
    3318              : static void
    3319            0 : expand_VEC_CONVERT (internal_fn, gcall *)
    3320              : {
    3321            0 :   gcc_unreachable ();
    3322              : }
    3323              : 
    3324              : /* Expand IFN_RAWMEMCHR internal function.  */
    3325              : 
    3326              : void
    3327            0 : expand_RAWMEMCHR (internal_fn, gcall *stmt)
    3328              : {
    3329            0 :   expand_operand ops[3];
    3330              : 
    3331            0 :   tree lhs = gimple_call_lhs (stmt);
    3332            0 :   if (!lhs)
    3333            0 :     return;
    3334            0 :   machine_mode lhs_mode = TYPE_MODE (TREE_TYPE (lhs));
    3335            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3336            0 :   create_call_lhs_operand (&ops[0], lhs_rtx, lhs_mode);
    3337              : 
    3338            0 :   tree mem = gimple_call_arg (stmt, 0);
    3339            0 :   rtx mem_rtx = get_memory_rtx (mem, NULL);
    3340            0 :   create_fixed_operand (&ops[1], mem_rtx);
    3341              : 
    3342            0 :   tree pattern = gimple_call_arg (stmt, 1);
    3343            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (pattern));
    3344            0 :   rtx pattern_rtx = expand_normal (pattern);
    3345            0 :   create_input_operand (&ops[2], pattern_rtx, mode);
    3346              : 
    3347            0 :   insn_code icode = direct_optab_handler (rawmemchr_optab, mode);
    3348              : 
    3349            0 :   expand_insn (icode, 3, ops);
    3350            0 :   assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    3351              : }
    3352              : 
    3353              : /* Expand the IFN_UNIQUE function according to its first argument.  */
    3354              : 
    3355              : static void
    3356            0 : expand_UNIQUE (internal_fn, gcall *stmt)
    3357              : {
    3358            0 :   rtx pattern = NULL_RTX;
    3359            0 :   enum ifn_unique_kind kind
    3360            0 :     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (stmt, 0));
    3361              : 
    3362            0 :   switch (kind)
    3363              :     {
    3364            0 :     default:
    3365            0 :       gcc_unreachable ();
    3366              : 
    3367            0 :     case IFN_UNIQUE_UNSPEC:
    3368            0 :       if (targetm.have_unique ())
    3369            0 :         pattern = targetm.gen_unique ();
    3370              :       break;
    3371              : 
    3372            0 :     case IFN_UNIQUE_OACC_FORK:
    3373            0 :     case IFN_UNIQUE_OACC_JOIN:
    3374            0 :       if (targetm.have_oacc_fork () && targetm.have_oacc_join ())
    3375              :         {
    3376            0 :           tree lhs = gimple_call_lhs (stmt);
    3377            0 :           rtx target = const0_rtx;
    3378              : 
    3379            0 :           if (lhs)
    3380            0 :             target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3381              : 
    3382            0 :           rtx data_dep = expand_normal (gimple_call_arg (stmt, 1));
    3383            0 :           rtx axis = expand_normal (gimple_call_arg (stmt, 2));
    3384              : 
    3385            0 :           if (kind == IFN_UNIQUE_OACC_FORK)
    3386            0 :             pattern = targetm.gen_oacc_fork (target, data_dep, axis);
    3387              :           else
    3388            0 :             pattern = targetm.gen_oacc_join (target, data_dep, axis);
    3389              :         }
    3390              :       else
    3391            0 :         gcc_unreachable ();
    3392              :       break;
    3393              :     }
    3394              : 
    3395            0 :   if (pattern)
    3396            0 :     emit_insn (pattern);
    3397            0 : }
    3398              : 
    3399              : /* Expand the IFN_DEFERRED_INIT function:
    3400              :    LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, NAME of the DECL);
    3401              : 
    3402              :    Initialize the LHS with zero/pattern according to its second argument
    3403              :    INIT_TYPE:
    3404              :    if INIT_TYPE is AUTO_INIT_ZERO, use zeroes to initialize;
    3405              :    if INIT_TYPE is AUTO_INIT_PATTERN, use 0xFE byte-repeatable pattern
    3406              :      to initialize;
    3407              :    The LHS variable is initialized including paddings.
    3408              :    The reasons to choose 0xFE for pattern initialization are:
    3409              :      1. It is a non-canonical virtual address on x86_64, and at the
    3410              :         high end of the i386 kernel address space.
    3411              :      2. It is a very large float value (-1.694739530317379e+38).
    3412              :      3. It is also an unusual number for integers.  */
    3413              : #define INIT_PATTERN_VALUE  0xFE
    3414              : static void
    3415        29871 : expand_DEFERRED_INIT (internal_fn, gcall *stmt)
    3416              : {
    3417        29871 :   tree lhs = gimple_call_lhs (stmt);
    3418        29871 :   tree var_size = gimple_call_arg (stmt, 0);
    3419        29871 :   enum auto_init_type init_type
    3420        29871 :     = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
    3421        29871 :   bool reg_lhs = true;
    3422              : 
    3423        29871 :   tree var_type = TREE_TYPE (lhs);
    3424        29871 :   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
    3425              : 
    3426        29871 :   if (TREE_CODE (lhs) == SSA_NAME)
    3427              :     reg_lhs = true;
    3428              :   else
    3429              :     {
    3430              :       tree lhs_base = lhs;
    3431        18744 :       while (handled_component_p (lhs_base))
    3432            4 :         lhs_base = TREE_OPERAND (lhs_base, 0);
    3433        18740 :       reg_lhs = (mem_ref_refers_to_non_mem_p (lhs_base)
    3434        18740 :                  || non_mem_decl_p (lhs_base));
    3435              :       /* If this expands to a register and the underlying decl is wrapped in
    3436              :          a MEM_REF that just serves as an access type change expose the decl
    3437              :          if it is of correct size.  This avoids a situation as in PR103271
    3438              :          if the target does not support a direct move to the registers mode.  */
    3439         1665 :       if (reg_lhs
    3440         1665 :           && TREE_CODE (lhs_base) == MEM_REF
    3441            4 :           && TREE_CODE (TREE_OPERAND (lhs_base, 0)) == ADDR_EXPR
    3442            4 :           && DECL_P (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))
    3443            4 :           && integer_zerop (TREE_OPERAND (lhs_base, 1))
    3444            4 :           && tree_fits_uhwi_p (var_size)
    3445            4 :           && tree_int_cst_equal
    3446            4 :                (var_size,
    3447            4 :                 DECL_SIZE_UNIT (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))))
    3448              :         {
    3449            4 :           lhs = TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0);
    3450            4 :           var_type = TREE_TYPE (lhs);
    3451              :         }
    3452              :     }
    3453              : 
    3454        18740 :   if (!reg_lhs)
    3455              :     {
    3456              :       /* If the variable is not in register, expand to a memset
    3457              :          to initialize it.  */
    3458        17075 :       mark_addressable (lhs);
    3459        17075 :       tree var_addr = build_fold_addr_expr (lhs);
    3460              : 
    3461        17075 :       tree value = (init_type == AUTO_INIT_PATTERN)
    3462        17075 :                     ? build_int_cst (integer_type_node,
    3463              :                                      INIT_PATTERN_VALUE)
    3464        16999 :                     : integer_zero_node;
    3465        34150 :       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
    3466              :                                      3, var_addr, value, var_size);
    3467              :       /* Expand this memset call.  */
    3468        17075 :       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
    3469              :     }
    3470              :   else
    3471              :     {
    3472              :       /* If this variable is in a register use expand_assignment.
    3473              :          For boolean scalars force zero-init.  */
    3474        12796 :       tree init;
    3475        12796 :       scalar_int_mode var_mode;
    3476        12796 :       if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE
    3477        12545 :           && tree_fits_uhwi_p (var_size)
    3478        12545 :           && (init_type == AUTO_INIT_PATTERN
    3479        12461 :               || !is_gimple_reg_type (var_type))
    3480         1749 :           && int_mode_for_size (tree_to_uhwi (var_size) * BITS_PER_UNIT,
    3481        12801 :                                 0).exists (&var_mode)
    3482        14545 :           && have_insn_for (SET, var_mode))
    3483              :         {
    3484         1744 :           unsigned HOST_WIDE_INT total_bytes = tree_to_uhwi (var_size);
    3485         1744 :           unsigned char *buf = XALLOCAVEC (unsigned char, total_bytes);
    3486         1744 :           memset (buf, (init_type == AUTO_INIT_PATTERN
    3487              :                         ? INIT_PATTERN_VALUE : 0), total_bytes);
    3488         1744 :           tree itype = build_nonstandard_integer_type
    3489         1744 :                          (total_bytes * BITS_PER_UNIT, 1);
    3490         1744 :           wide_int w = wi::from_buffer (buf, total_bytes);
    3491         1744 :           init = wide_int_to_tree (itype, w);
    3492              :           /* Pun the LHS to make sure its type has constant size
    3493              :              unless it is an SSA name where that's already known.  */
    3494         1744 :           if (TREE_CODE (lhs) != SSA_NAME)
    3495         1665 :             lhs = build1 (VIEW_CONVERT_EXPR, itype, lhs);
    3496              :           else
    3497           79 :             init = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), init);
    3498         1744 :         }
    3499              :       else
    3500              :         /* Use zero-init also for variable-length sizes.  */
    3501        11052 :         init = build_zero_cst (var_type);
    3502              : 
    3503        12796 :       expand_assignment (lhs, init, false);
    3504              :     }
    3505        29871 : }
    3506              : 
    3507              : /* Expand the IFN_ACCESS_WITH_SIZE function:
    3508              :    ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE,
    3509              :                      TYPE_OF_SIZE + ACCESS_MODE, TYPE_SIZE_UNIT for element)
    3510              :    which returns the REF_TO_OBJ same as the 1st argument;
    3511              : 
    3512              :    1st argument REF_TO_OBJ: The reference to the object;
    3513              :    2nd argument REF_TO_SIZE: The reference to the size of the object,
    3514              :    3rd argument TYPE_OF_SIZE + ACCESS_MODE: An integer constant with a pointer
    3515              :      TYPE.
    3516              :      The pointee TYPE of the pointer TYPE is the TYPE of the object referenced
    3517              :         by REF_TO_SIZE.
    3518              :      The integer constant value represents the ACCESS_MODE:
    3519              :         0: none
    3520              :         1: read_only
    3521              :         2: write_only
    3522              :         3: read_write
    3523              : 
    3524              :    4th argument: The TYPE_SIZE_UNIT of the element TYPE of the array.
    3525              : 
    3526              :    Both the return type and the type of the first argument of this
    3527              :    function have been converted from the incomplete array type to
    3528              :    the corresponding pointer type.
    3529              : 
    3530              :    For each call to a .ACCESS_WITH_SIZE, replace it with its 1st argument.  */
    3531              : 
    3532              : static void
    3533          288 : expand_ACCESS_WITH_SIZE (internal_fn, gcall *stmt)
    3534              : {
    3535          288 :   tree lhs = gimple_call_lhs (stmt);
    3536          288 :   tree ref_to_obj = gimple_call_arg (stmt, 0);
    3537          288 :   if (lhs)
    3538          288 :     expand_assignment (lhs, ref_to_obj, false);
    3539          288 : }
    3540              : 
    3541              : /* The size of an OpenACC compute dimension.  */
    3542              : 
    3543              : static void
    3544         5695 : expand_GOACC_DIM_SIZE (internal_fn, gcall *stmt)
    3545              : {
    3546         5695 :   tree lhs = gimple_call_lhs (stmt);
    3547              : 
    3548         5695 :   if (!lhs)
    3549              :     return;
    3550              : 
    3551         5695 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3552         5695 :   if (targetm.have_oacc_dim_size ())
    3553              :     {
    3554            0 :       rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
    3555              :                              VOIDmode, EXPAND_NORMAL);
    3556            0 :       emit_insn (targetm.gen_oacc_dim_size (target, dim));
    3557              :     }
    3558              :   else
    3559         5695 :     emit_move_insn (target, GEN_INT (1));
    3560              : }
    3561              : 
    3562              : /* The position of an OpenACC execution engine along one compute axis.  */
    3563              : 
    3564              : static void
    3565         4567 : expand_GOACC_DIM_POS (internal_fn, gcall *stmt)
    3566              : {
    3567         4567 :   tree lhs = gimple_call_lhs (stmt);
    3568              : 
    3569         4567 :   if (!lhs)
    3570              :     return;
    3571              : 
    3572         4567 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3573         4567 :   if (targetm.have_oacc_dim_pos ())
    3574              :     {
    3575            0 :       rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
    3576              :                              VOIDmode, EXPAND_NORMAL);
    3577            0 :       emit_insn (targetm.gen_oacc_dim_pos (target, dim));
    3578              :     }
    3579              :   else
    3580         4567 :     emit_move_insn (target, const0_rtx);
    3581              : }
    3582              : 
    3583              : /* This is expanded by oacc_device_lower pass.  */
    3584              : 
    3585              : static void
    3586            0 : expand_GOACC_LOOP (internal_fn, gcall *)
    3587              : {
    3588            0 :   gcc_unreachable ();
    3589              : }
    3590              : 
    3591              : /* This is expanded by oacc_device_lower pass.  */
    3592              : 
    3593              : static void
    3594            0 : expand_GOACC_REDUCTION (internal_fn, gcall *)
    3595              : {
    3596            0 :   gcc_unreachable ();
    3597              : }
    3598              : 
    3599              : /* This is expanded by oacc_device_lower pass.  */
    3600              : 
    3601              : static void
    3602            0 : expand_GOACC_TILE (internal_fn, gcall *)
    3603              : {
    3604            0 :   gcc_unreachable ();
    3605              : }
    3606              : 
    3607              : /* Set errno to EDOM.  */
    3608              : 
    3609              : static void
    3610            0 : expand_SET_EDOM (internal_fn, gcall *)
    3611              : {
    3612              : #ifdef TARGET_EDOM
    3613              : #ifdef GEN_ERRNO_RTX
    3614              :   rtx errno_rtx = GEN_ERRNO_RTX;
    3615              : #else
    3616              :   rtx errno_rtx = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
    3617              : #endif
    3618              :   emit_move_insn (errno_rtx,
    3619              :                   gen_int_mode (TARGET_EDOM, GET_MODE (errno_rtx)));
    3620              : #else
    3621            0 :   gcc_unreachable ();
    3622              : #endif
    3623              : }
    3624              : 
    3625              : /* Expand atomic bit test and set.  */
    3626              : 
    3627              : static void
    3628          146 : expand_ATOMIC_BIT_TEST_AND_SET (internal_fn, gcall *call)
    3629              : {
    3630          146 :   expand_ifn_atomic_bit_test_and (call);
    3631          146 : }
    3632              : 
    3633              : /* Expand atomic bit test and complement.  */
    3634              : 
    3635              : static void
    3636          146 : expand_ATOMIC_BIT_TEST_AND_COMPLEMENT (internal_fn, gcall *call)
    3637              : {
    3638          146 :   expand_ifn_atomic_bit_test_and (call);
    3639          146 : }
    3640              : 
    3641              : /* Expand atomic bit test and reset.  */
    3642              : 
    3643              : static void
    3644          135 : expand_ATOMIC_BIT_TEST_AND_RESET (internal_fn, gcall *call)
    3645              : {
    3646          135 :   expand_ifn_atomic_bit_test_and (call);
    3647          135 : }
    3648              : 
    3649              : /* Expand atomic bit test and set.  */
    3650              : 
    3651              : static void
    3652        13870 : expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call)
    3653              : {
    3654        13870 :   expand_ifn_atomic_compare_exchange (call);
    3655        13870 : }
    3656              : 
    3657              : /* Expand atomic add fetch and cmp with 0.  */
    3658              : 
    3659              : static void
    3660          885 : expand_ATOMIC_ADD_FETCH_CMP_0 (internal_fn, gcall *call)
    3661              : {
    3662          885 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3663          885 : }
    3664              : 
    3665              : /* Expand atomic sub fetch and cmp with 0.  */
    3666              : 
    3667              : static void
    3668          738 : expand_ATOMIC_SUB_FETCH_CMP_0 (internal_fn, gcall *call)
    3669              : {
    3670          738 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3671          738 : }
    3672              : 
    3673              : /* Expand atomic and fetch and cmp with 0.  */
    3674              : 
    3675              : static void
    3676          176 : expand_ATOMIC_AND_FETCH_CMP_0 (internal_fn, gcall *call)
    3677              : {
    3678          176 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3679          176 : }
    3680              : 
    3681              : /* Expand atomic or fetch and cmp with 0.  */
    3682              : 
    3683              : static void
    3684          112 : expand_ATOMIC_OR_FETCH_CMP_0 (internal_fn, gcall *call)
    3685              : {
    3686          112 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3687          112 : }
    3688              : 
    3689              : /* Expand atomic xor fetch and cmp with 0.  */
    3690              : 
    3691              : static void
    3692          176 : expand_ATOMIC_XOR_FETCH_CMP_0 (internal_fn, gcall *call)
    3693              : {
    3694          176 :   expand_ifn_atomic_op_fetch_cmp_0 (call);
    3695          176 : }
    3696              : 
    3697              : /* Expand LAUNDER to assignment, lhs = arg0.  */
    3698              : 
    3699              : static void
    3700           29 : expand_LAUNDER (internal_fn, gcall *call)
    3701              : {
    3702           29 :   tree lhs = gimple_call_lhs (call);
    3703              : 
    3704           29 :   if (!lhs)
    3705              :     return;
    3706              : 
    3707           28 :   expand_assignment (lhs, gimple_call_arg (call, 0), false);
    3708              : }
    3709              : 
    3710              : /* Expand {MASK_,}SCATTER_STORE{S,U} call CALL using optab OPTAB.  */
    3711              : 
    3712              : static void
    3713            0 : expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
    3714              : {
    3715            0 :   internal_fn ifn = gimple_call_internal_fn (stmt);
    3716            0 :   int rhs_index = internal_fn_stored_value_index (ifn);
    3717            0 :   tree base = gimple_call_arg (stmt, 0);
    3718            0 :   tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
    3719            0 :   tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
    3720            0 :   tree rhs = gimple_call_arg (stmt, rhs_index);
    3721              : 
    3722            0 :   rtx base_rtx = expand_normal (base);
    3723            0 :   rtx offset_rtx = expand_normal (offset);
    3724            0 :   HOST_WIDE_INT scale_int = tree_to_shwi (scale);
    3725            0 :   rtx rhs_rtx = expand_normal (rhs);
    3726              : 
    3727            0 :   class expand_operand ops[8];
    3728            0 :   int i = 0;
    3729            0 :   create_address_operand (&ops[i++], base_rtx);
    3730            0 :   create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
    3731            0 :   create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
    3732            0 :   create_integer_operand (&ops[i++], scale_int);
    3733            0 :   create_input_operand (&ops[i++], rhs_rtx, TYPE_MODE (TREE_TYPE (rhs)));
    3734            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3735              : 
    3736            0 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (rhs)),
    3737            0 :                                            TYPE_MODE (TREE_TYPE (offset)));
    3738            0 :   expand_insn (icode, i, ops);
    3739            0 : }
    3740              : 
    3741              : /* Expand {MASK_,}GATHER_LOAD call CALL using optab OPTAB.  */
    3742              : 
    3743              : static void
    3744            0 : expand_gather_load_optab_fn (internal_fn ifn, gcall *stmt, direct_optab optab)
    3745              : {
    3746            0 :   tree lhs = gimple_call_lhs (stmt);
    3747            0 :   tree base = gimple_call_arg (stmt, 0);
    3748            0 :   tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
    3749            0 :   tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
    3750              : 
    3751            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3752            0 :   rtx base_rtx = expand_normal (base);
    3753            0 :   rtx offset_rtx = expand_normal (offset);
    3754            0 :   HOST_WIDE_INT scale_int = tree_to_shwi (scale);
    3755              : 
    3756            0 :   int i = 0;
    3757            0 :   class expand_operand ops[9];
    3758            0 :   create_call_lhs_operand (&ops[i++], lhs_rtx, TYPE_MODE (TREE_TYPE (lhs)));
    3759            0 :   create_address_operand (&ops[i++], base_rtx);
    3760            0 :   create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
    3761            0 :   create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
    3762            0 :   create_integer_operand (&ops[i++], scale_int);
    3763            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3764            0 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)),
    3765            0 :                                            TYPE_MODE (TREE_TYPE (offset)));
    3766            0 :   expand_insn (icode, i, ops);
    3767            0 :   assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    3768            0 : }
    3769              : 
    3770              : /* Expand MASK_LEN_STRIDED_LOAD call CALL by optab OPTAB.  */
    3771              : 
    3772              : static void
    3773            0 : expand_strided_load_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
    3774              :                               direct_optab optab)
    3775              : {
    3776            0 :   tree lhs = gimple_call_lhs (stmt);
    3777            0 :   tree base = gimple_call_arg (stmt, 0);
    3778            0 :   tree stride = gimple_call_arg (stmt, 1);
    3779              : 
    3780            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3781            0 :   rtx base_rtx = expand_normal (base);
    3782            0 :   rtx stride_rtx = expand_normal (stride);
    3783              : 
    3784            0 :   unsigned i = 0;
    3785            0 :   class expand_operand ops[7];
    3786            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
    3787              : 
    3788            0 :   create_output_operand (&ops[i++], lhs_rtx, mode);
    3789            0 :   create_address_operand (&ops[i++], base_rtx);
    3790            0 :   create_address_operand (&ops[i++], stride_rtx);
    3791              : 
    3792            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3793            0 :   expand_insn (direct_optab_handler (optab, mode), i, ops);
    3794              : 
    3795            0 :   if (!rtx_equal_p (lhs_rtx, ops[0].value))
    3796            0 :     emit_move_insn (lhs_rtx, ops[0].value);
    3797            0 : }
    3798              : 
    3799              : /* Expand MASK_LEN_STRIDED_STORE call CALL by optab OPTAB.  */
    3800              : 
    3801              : static void
    3802            0 : expand_strided_store_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
    3803              :                                direct_optab optab)
    3804              : {
    3805            0 :   internal_fn fn = gimple_call_internal_fn (stmt);
    3806            0 :   int rhs_index = internal_fn_stored_value_index (fn);
    3807              : 
    3808            0 :   tree base = gimple_call_arg (stmt, 0);
    3809            0 :   tree stride = gimple_call_arg (stmt, 1);
    3810            0 :   tree rhs = gimple_call_arg (stmt, rhs_index);
    3811              : 
    3812            0 :   rtx base_rtx = expand_normal (base);
    3813            0 :   rtx stride_rtx = expand_normal (stride);
    3814            0 :   rtx rhs_rtx = expand_normal (rhs);
    3815              : 
    3816            0 :   unsigned i = 0;
    3817            0 :   class expand_operand ops[6];
    3818            0 :   machine_mode mode = TYPE_MODE (TREE_TYPE (rhs));
    3819              : 
    3820            0 :   create_address_operand (&ops[i++], base_rtx);
    3821            0 :   create_address_operand (&ops[i++], stride_rtx);
    3822            0 :   create_input_operand (&ops[i++], rhs_rtx, mode);
    3823              : 
    3824            0 :   i = add_mask_else_and_len_args (ops, i, stmt);
    3825            0 :   expand_insn (direct_optab_handler (optab, mode), i, ops);
    3826            0 : }
    3827              : 
    3828              : /* Helper for expand_DIVMOD.  Return true if the sequence starting with
    3829              :    INSN contains any call insns or insns with {,U}{DIV,MOD} rtxes.  */
    3830              : 
    3831              : static bool
    3832          844 : contains_call_div_mod (rtx_insn *insn)
    3833              : {
    3834          844 :   subrtx_iterator::array_type array;
    3835         4849 :   for (; insn; insn = NEXT_INSN (insn))
    3836         4849 :     if (CALL_P (insn))
    3837              :       return true;
    3838         4005 :     else if (INSN_P (insn))
    3839        17912 :       FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
    3840        13907 :         switch (GET_CODE (*iter))
    3841              :           {
    3842            0 :           case CALL:
    3843            0 :           case DIV:
    3844            0 :           case UDIV:
    3845            0 :           case MOD:
    3846            0 :           case UMOD:
    3847            0 :             return true;
    3848        13907 :           default:
    3849        13907 :             break;
    3850              :           }
    3851              :   return false;
    3852          844 :  }
    3853              : 
    3854              : /* Expand DIVMOD() using:
    3855              :  a) optab handler for udivmod/sdivmod if it is available.
    3856              :  b) If optab_handler doesn't exist, generate call to
    3857              :     target-specific divmod libfunc.  */
    3858              : 
    3859              : static void
    3860        11571 : expand_DIVMOD (internal_fn, gcall *call_stmt)
    3861              : {
    3862        11571 :   tree lhs = gimple_call_lhs (call_stmt);
    3863        11571 :   tree arg0 = gimple_call_arg (call_stmt, 0);
    3864        11571 :   tree arg1 = gimple_call_arg (call_stmt, 1);
    3865              : 
    3866        11571 :   gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
    3867        11571 :   tree type = TREE_TYPE (TREE_TYPE (lhs));
    3868        11571 :   machine_mode mode = TYPE_MODE (type);
    3869        11571 :   bool unsignedp = TYPE_UNSIGNED (type);
    3870        11571 :   optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab;
    3871              : 
    3872        11571 :   rtx op0 = expand_normal (arg0);
    3873        11571 :   rtx op1 = expand_normal (arg1);
    3874        11571 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    3875              : 
    3876        11571 :   rtx quotient = NULL_RTX, remainder = NULL_RTX;
    3877        11571 :   rtx_insn *insns = NULL;
    3878              : 
    3879        11571 :   if (TREE_CODE (arg1) == INTEGER_CST)
    3880              :     {
    3881              :       /* For DIVMOD by integral constants, there could be efficient code
    3882              :          expanded inline e.g. using shifts and plus/minus.  Try to expand
    3883              :          the division and modulo and if it emits any library calls or any
    3884              :          {,U}{DIV,MOD} rtxes throw it away and use a divmod optab or
    3885              :          divmod libcall.  */
    3886         1238 :       scalar_int_mode int_mode;
    3887         1238 :       if (remainder == NULL_RTX
    3888         1238 :           && optimize
    3889         1238 :           && CONST_INT_P (op1)
    3890         1232 :           && !pow2p_hwi (INTVAL (op1))
    3891         2464 :           && is_int_mode (TYPE_MODE (type), &int_mode)
    3892         1428 :           && GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD
    3893         1232 :           && optab_handler (and_optab, word_mode) != CODE_FOR_nothing
    3894         1232 :           && optab_handler (add_optab, word_mode) != CODE_FOR_nothing
    3895         1232 :           && optimize_insn_for_speed_p ())
    3896              :         {
    3897         1229 :           rtx_insn *last = get_last_insn ();
    3898         1229 :           remainder = NULL_RTX;
    3899         3687 :           quotient = expand_doubleword_divmod (int_mode, op0, op1, &remainder,
    3900         1229 :                                                TYPE_UNSIGNED (type));
    3901         1229 :           if (quotient != NULL_RTX)
    3902              :             {
    3903          394 :               if (optab_handler (mov_optab, int_mode) != CODE_FOR_nothing)
    3904              :                 {
    3905          394 :                   rtx_insn *move = emit_move_insn (quotient, quotient);
    3906          788 :                   set_dst_reg_note (move, REG_EQUAL,
    3907          394 :                                     gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
    3908              :                                                     ? UDIV : DIV, int_mode,
    3909              :                                                     copy_rtx (op0), op1),
    3910              :                                     quotient);
    3911          394 :                   move = emit_move_insn (remainder, remainder);
    3912          788 :                   set_dst_reg_note (move, REG_EQUAL,
    3913          394 :                                     gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
    3914              :                                                     ? UMOD : MOD, int_mode,
    3915              :                                                     copy_rtx (op0), op1),
    3916              :                                     quotient);
    3917              :                 }
    3918              :             }
    3919              :           else
    3920          835 :             delete_insns_since (last);
    3921              :         }
    3922              : 
    3923         1238 :       if (remainder == NULL_RTX)
    3924              :         {
    3925          844 :           struct separate_ops ops;
    3926          844 :           ops.code = TRUNC_DIV_EXPR;
    3927          844 :           ops.type = type;
    3928          844 :           ops.op0 = make_tree (ops.type, op0);
    3929          844 :           ops.op1 = arg1;
    3930          844 :           ops.op2 = NULL_TREE;
    3931          844 :           ops.location = gimple_location (call_stmt);
    3932          844 :           start_sequence ();
    3933          844 :           quotient = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
    3934          844 :           if (contains_call_div_mod (get_insns ()))
    3935          844 :             quotient = NULL_RTX;
    3936              :           else
    3937              :             {
    3938            0 :               ops.code = TRUNC_MOD_EXPR;
    3939            0 :               remainder = expand_expr_real_2 (&ops, NULL_RTX, mode,
    3940              :                                               EXPAND_NORMAL);
    3941            0 :               if (contains_call_div_mod (get_insns ()))
    3942            0 :                 remainder = NULL_RTX;
    3943              :             }
    3944          844 :           if (remainder)
    3945            0 :             insns = get_insns ();
    3946          844 :           end_sequence ();
    3947              :         }
    3948              :     }
    3949              : 
    3950        11571 :   if (remainder)
    3951          394 :     emit_insn (insns);
    3952              : 
    3953              :   /* Check if optab_handler exists for divmod_optab for given mode.  */
    3954        11177 :   else if (optab_handler (tab, mode) != CODE_FOR_nothing)
    3955              :     {
    3956        10280 :       quotient = gen_reg_rtx (mode);
    3957        10280 :       remainder = gen_reg_rtx (mode);
    3958        10280 :       expand_twoval_binop (tab, op0, op1, quotient, remainder, unsignedp);
    3959              :     }
    3960              : 
    3961              :   /* Generate call to divmod libfunc if it exists.  */
    3962          897 :   else if (rtx libfunc = optab_libfunc (tab, mode))
    3963          897 :     targetm.expand_divmod_libfunc (libfunc, mode, op0, op1,
    3964              :                                    &quotient, &remainder);
    3965              : 
    3966              :   else
    3967            0 :     gcc_unreachable ();
    3968              : 
    3969              :   /* Wrap the return value (quotient, remainder) within COMPLEX_EXPR.  */
    3970        23142 :   expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
    3971        11571 :                        make_tree (TREE_TYPE (arg0), quotient),
    3972        11571 :                        make_tree (TREE_TYPE (arg1), remainder)),
    3973              :                target, VOIDmode, EXPAND_NORMAL);
    3974        11571 : }
    3975              : 
    3976              : /* Expand a NOP.  */
    3977              : 
    3978              : static void
    3979            1 : expand_NOP (internal_fn, gcall *)
    3980              : {
    3981              :   /* Nothing.  But it shouldn't really prevail.  */
    3982            1 : }
    3983              : 
    3984              : /* Coroutines, all should have been processed at this stage.  */
    3985              : 
    3986              : static void
    3987            0 : expand_CO_FRAME (internal_fn, gcall *)
    3988              : {
    3989            0 :   gcc_unreachable ();
    3990              : }
    3991              : 
    3992              : static void
    3993            0 : expand_CO_YIELD (internal_fn, gcall *)
    3994              : {
    3995            0 :   gcc_unreachable ();
    3996              : }
    3997              : 
    3998              : static void
    3999            0 : expand_CO_SUSPN (internal_fn, gcall *)
    4000              : {
    4001            0 :   gcc_unreachable ();
    4002              : }
    4003              : 
    4004              : static void
    4005            0 : expand_CO_ACTOR (internal_fn, gcall *)
    4006              : {
    4007            0 :   gcc_unreachable ();
    4008              : }
    4009              : 
    4010              : /* Expand a call to FN using the operands in STMT.  FN has a single
    4011              :    output operand and NARGS input operands.  */
    4012              : 
    4013              : static void
    4014        79609 : expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
    4015              :                         unsigned int nargs)
    4016              : {
    4017        79609 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4018        79609 :   insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
    4019        79609 :   expand_fn_using_insn (stmt, icode, 1, nargs);
    4020        79609 : }
    4021              : 
    4022              : /* Expand WHILE_ULT call STMT using optab OPTAB.  */
    4023              : 
    4024              : static void
    4025            0 : expand_while_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
    4026              : {
    4027            0 :   expand_operand ops[4];
    4028            0 :   tree rhs_type[2];
    4029              : 
    4030            0 :   tree lhs = gimple_call_lhs (stmt);
    4031            0 :   tree lhs_type = TREE_TYPE (lhs);
    4032            0 :   rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    4033            0 :   create_call_lhs_operand (&ops[0], lhs_rtx, TYPE_MODE (lhs_type));
    4034              : 
    4035            0 :   for (unsigned int i = 0; i < 2; ++i)
    4036              :     {
    4037            0 :       tree rhs = gimple_call_arg (stmt, i);
    4038            0 :       rhs_type[i] = TREE_TYPE (rhs);
    4039            0 :       rtx rhs_rtx = expand_normal (rhs);
    4040            0 :       create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type[i]));
    4041              :     }
    4042              : 
    4043            0 :   int opcnt;
    4044            0 :   if (!VECTOR_MODE_P (TYPE_MODE (lhs_type)))
    4045              :     {
    4046              :       /* When the mask is an integer mode the exact vector length may not
    4047              :          be clear to the backend, so we pass it in operand[3].
    4048              :          Use the vector in arg2 for the most reliable intended size.  */
    4049            0 :       tree type = TREE_TYPE (gimple_call_arg (stmt, 2));
    4050            0 :       create_integer_operand (&ops[3], TYPE_VECTOR_SUBPARTS (type));
    4051            0 :       opcnt = 4;
    4052              :     }
    4053              :   else
    4054              :     /* The mask has a vector type so the length operand is unnecessary.  */
    4055              :     opcnt = 3;
    4056              : 
    4057            0 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (rhs_type[0]),
    4058            0 :                                            TYPE_MODE (lhs_type));
    4059              : 
    4060            0 :   expand_insn (icode, opcnt, ops);
    4061            0 :   assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    4062            0 : }
    4063              : 
    4064              : /* Expand a call to a convert-like optab using the operands in STMT.
    4065              :    FN has a single output operand and NARGS input operands.  */
    4066              : 
    4067              : static void
    4068          444 : expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab,
    4069              :                          unsigned int nargs)
    4070              : {
    4071          444 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4072          444 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (types.first),
    4073          444 :                                           TYPE_MODE (types.second));
    4074          444 :   expand_fn_using_insn (stmt, icode, 1, nargs);
    4075          444 : }
    4076              : 
    4077              : /* Expand CRC call STMT.  */
    4078              : 
    4079              : static void
    4080          242 : expand_crc_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab)
    4081              : {
    4082          242 :   tree lhs = gimple_call_lhs (stmt);
    4083          242 :   tree rhs1 = gimple_call_arg (stmt, 0); // crc
    4084          242 :   tree rhs2 = gimple_call_arg (stmt, 1); // data
    4085          242 :   tree rhs3 = gimple_call_arg (stmt, 2); // polynomial
    4086              : 
    4087          242 :   tree result_type = TREE_TYPE (lhs);
    4088          242 :   tree data_type = TREE_TYPE (rhs2);
    4089              : 
    4090          242 :   gcc_assert (TYPE_MODE (result_type) >= TYPE_MODE (data_type));
    4091              : 
    4092          242 :   rtx dest = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    4093          242 :   rtx crc = expand_normal (rhs1);
    4094          242 :   rtx data = expand_normal (rhs2);
    4095          242 :   rtx polynomial;
    4096          242 :   if (TREE_CODE (rhs3) != INTEGER_CST)
    4097              :     {
    4098            0 :       error ("third argument to %<crc%> builtins must be a constant");
    4099            0 :       polynomial = const0_rtx;
    4100              :     }
    4101              :   else
    4102          242 :     polynomial = convert_to_mode (TYPE_MODE (result_type), expand_normal (rhs3), 0);
    4103              : 
    4104              :   /* Use target specific expansion if it exists.
    4105              :      Otherwise, generate table-based CRC.  */
    4106          242 :   if (direct_internal_fn_supported_p (fn, tree_pair (data_type, result_type),
    4107              :                                       OPTIMIZE_FOR_SPEED))
    4108              :     {
    4109            5 :       class expand_operand ops[4];
    4110              : 
    4111            5 :       if (dump_file && (dump_flags & TDF_DETAILS))
    4112              :         {
    4113            0 :           fprintf (dump_file,
    4114              :                    ";; using optab for crc_%u_polynomial_"
    4115              :                    HOST_WIDE_INT_PRINT_HEX "\n",
    4116            0 :                    GET_MODE_BITSIZE (GET_MODE (dest)).to_constant (),
    4117            0 :                    TREE_INT_CST_LOW (rhs3));
    4118              :         }
    4119              : 
    4120            5 :       create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
    4121            5 :       create_input_operand (&ops[1], crc, TYPE_MODE (result_type));
    4122            5 :       create_input_operand (&ops[2], data, TYPE_MODE (data_type));
    4123            5 :       create_input_operand (&ops[3], polynomial, TYPE_MODE (result_type));
    4124            5 :       insn_code icode = convert_optab_handler (optab, TYPE_MODE (data_type),
    4125            5 :                                                TYPE_MODE (result_type));
    4126            5 :       expand_insn (icode, 4, ops);
    4127            5 :       assign_call_lhs (lhs, dest, &ops[0]);
    4128              :     }
    4129              :   else
    4130              :     {
    4131              :       /* We're bypassing all the operand conversions that are done in the
    4132              :          case when we get an icode, operands and pass that off to expand_insn.
    4133              : 
    4134              :          That path has special case handling for promoted return values which
    4135              :          we must emulate here (is the same kind of special treatment ever
    4136              :          needed for input arguments here?).
    4137              : 
    4138              :          In particular we do not want to store directly into a promoted
    4139              :          SUBREG destination, instead store into a suitably sized pseudo.  */
    4140          237 :       rtx orig_dest = dest;
    4141          237 :       if (SUBREG_P (dest) && SUBREG_PROMOTED_VAR_P (dest))
    4142            0 :         dest = gen_reg_rtx (GET_MODE (dest));
    4143              : 
    4144              :       /* If it's IFN_CRC generate bit-forward CRC.  */
    4145          237 :       if (fn == IFN_CRC)
    4146          117 :         expand_crc_table_based (dest, crc, data, polynomial,
    4147          117 :                                 TYPE_MODE (data_type));
    4148              :       else
    4149              :         /* If it's IFN_CRC_REV generate bit-reversed CRC.  */
    4150          120 :         expand_reversed_crc_table_based (dest, crc, data, polynomial,
    4151          120 :                                          TYPE_MODE (data_type),
    4152              :                                          generate_reflecting_code_standard);
    4153              : 
    4154              :       /* Now get the return value where it needs to be, taking care to
    4155              :          ensure it's promoted appropriately if the ABI demands it.
    4156              : 
    4157              :          Re-use assign_call_lhs to handle the details.  */
    4158          237 :       class expand_operand ops[4];
    4159          237 :       create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
    4160          237 :       ops[0].value = dest;
    4161          237 :       assign_call_lhs (lhs, orig_dest, &ops[0]);
    4162              :     }
    4163          242 : }
    4164              : 
    4165              : /* Expand .REDUC_SBOOL_{AND,IOR,XOR}.  */
    4166              : 
    4167              : static void
    4168           33 : expand_reduc_sbool_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab)
    4169              : {
    4170           33 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4171           33 :   insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
    4172              : 
    4173              :   /* Below copied from expand_fn_using_insn.  */
    4174              : 
    4175           33 :   gcc_assert (icode != CODE_FOR_nothing);
    4176              : 
    4177           33 :   expand_operand *ops = XALLOCAVEC (expand_operand, 3);
    4178           33 :   rtx lhs_rtx = NULL_RTX;
    4179           33 :   tree lhs = gimple_call_lhs (stmt);
    4180           33 :   if (lhs)
    4181           33 :     lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    4182           33 :   create_call_lhs_operand (&ops[0], lhs_rtx,
    4183           33 :                            insn_data[icode].operand[0].mode);
    4184              : 
    4185           33 :   tree rhs = gimple_call_arg (stmt, 0);
    4186           33 :   tree rhs_type = TREE_TYPE (rhs);
    4187           33 :   rtx rhs_rtx = expand_normal (rhs);
    4188           33 :   gcc_assert (VECTOR_BOOLEAN_TYPE_P (rhs_type));
    4189           33 :   create_input_operand (&ops[1], rhs_rtx, TYPE_MODE (rhs_type));
    4190           33 :   if (SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)))
    4191              :     {
    4192           18 :       rtx nunits = GEN_INT (TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ());
    4193           18 :       gcc_assert (insn_operand_matches (icode, 2, nunits));
    4194           18 :       create_input_operand (&ops[2], nunits, SImode);
    4195              :     }
    4196           51 :   expand_insn (icode, SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)) ? 3 : 2, ops);
    4197           33 :   if (lhs_rtx)
    4198           33 :     assign_call_lhs (lhs, lhs_rtx, &ops[0]);
    4199           33 : }
    4200              : 
    4201              : /* Expanders for optabs that can use expand_direct_optab_fn.  */
    4202              : 
    4203              : #define expand_unary_optab_fn(FN, STMT, OPTAB) \
    4204              :   expand_direct_optab_fn (FN, STMT, OPTAB, 1)
    4205              : 
    4206              : #define expand_binary_optab_fn(FN, STMT, OPTAB) \
    4207              :   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
    4208              : 
    4209              : #define expand_ternary_optab_fn(FN, STMT, OPTAB) \
    4210              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4211              : 
    4212              : #define expand_cond_unary_optab_fn(FN, STMT, OPTAB) \
    4213              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4214              : 
    4215              : #define expand_cond_binary_optab_fn(FN, STMT, OPTAB) \
    4216              :   expand_direct_optab_fn (FN, STMT, OPTAB, 4)
    4217              : 
    4218              : #define expand_cond_ternary_optab_fn(FN, STMT, OPTAB) \
    4219              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4220              : 
    4221              : #define expand_cond_len_unary_optab_fn(FN, STMT, OPTAB) \
    4222              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4223              : 
    4224              : #define expand_cond_len_binary_optab_fn(FN, STMT, OPTAB) \
    4225              :   expand_direct_optab_fn (FN, STMT, OPTAB, 6)
    4226              : 
    4227              : #define expand_cond_len_ternary_optab_fn(FN, STMT, OPTAB) \
    4228              :   expand_direct_optab_fn (FN, STMT, OPTAB, 7)
    4229              : 
    4230              : #define expand_fold_extract_optab_fn(FN, STMT, OPTAB) \
    4231              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4232              : 
    4233              : #define expand_fold_len_extract_optab_fn(FN, STMT, OPTAB) \
    4234              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4235              : 
    4236              : #define expand_fold_left_optab_fn(FN, STMT, OPTAB) \
    4237              :   expand_direct_optab_fn (FN, STMT, OPTAB, 2)
    4238              : 
    4239              : #define expand_mask_fold_left_optab_fn(FN, STMT, OPTAB) \
    4240              :   expand_direct_optab_fn (FN, STMT, OPTAB, 3)
    4241              : 
    4242              : #define expand_mask_len_fold_left_optab_fn(FN, STMT, OPTAB) \
    4243              :   expand_direct_optab_fn (FN, STMT, OPTAB, 5)
    4244              : 
    4245              : #define expand_check_ptrs_optab_fn(FN, STMT, OPTAB) \
    4246              :   expand_direct_optab_fn (FN, STMT, OPTAB, 4)
    4247              : 
    4248              : #define expand_select_vl_optab_fn(FN, STMT, OPTAB) \
    4249              :   expand_convert_optab_fn (FN, STMT, OPTAB, 3)
    4250              : 
    4251              : /* Expanders for optabs that can use expand_convert_optab_fn.  */
    4252              : 
    4253              : #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \
    4254              :   expand_convert_optab_fn (FN, STMT, OPTAB, 1)
    4255              : 
    4256              : #define expand_vec_extract_optab_fn(FN, STMT, OPTAB) \
    4257              :   expand_convert_optab_fn (FN, STMT, OPTAB, 2)
    4258              : 
    4259              : /* RETURN_TYPE and ARGS are a return type and argument list that are
    4260              :    in principle compatible with FN (which satisfies direct_internal_fn_p).
    4261              :    Return the types that should be used to determine whether the
    4262              :    target supports FN.  */
    4263              : 
    4264              : tree_pair
    4265         8202 : direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
    4266              : {
    4267         8202 :   const direct_internal_fn_info &info = direct_internal_fn (fn);
    4268         8202 :   tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
    4269         8202 :   tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
    4270         8202 :   return tree_pair (type0, type1);
    4271              : }
    4272              : 
    4273              : /* CALL is a call whose return type and arguments are in principle
    4274              :    compatible with FN (which satisfies direct_internal_fn_p).  Return the
    4275              :    types that should be used to determine whether the target supports FN.  */
    4276              : 
    4277              : tree_pair
    4278       140813 : direct_internal_fn_types (internal_fn fn, gcall *call)
    4279              : {
    4280       140813 :   const direct_internal_fn_info &info = direct_internal_fn (fn);
    4281       140813 :   tree op0 = (info.type0 < 0
    4282       140813 :               ? gimple_call_lhs (call)
    4283       139337 :               : gimple_call_arg (call, info.type0));
    4284       140813 :   tree op1 = (info.type1 < 0
    4285       140813 :               ? gimple_call_lhs (call)
    4286       140772 :               : gimple_call_arg (call, info.type1));
    4287       140813 :   return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1));
    4288              : }
    4289              : 
    4290              : /* Return true if OPTAB is supported for TYPES (whose modes should be
    4291              :    the same) when the optimization type is OPT_TYPE.  Used for simple
    4292              :    direct optabs.  */
    4293              : 
    4294              : static bool
    4295      4015485 : direct_optab_supported_p (direct_optab optab, tree_pair types,
    4296              :                           optimization_type opt_type)
    4297              : {
    4298      4015485 :   machine_mode mode = TYPE_MODE (types.first);
    4299      4015485 :   gcc_checking_assert (mode == TYPE_MODE (types.second));
    4300      4015485 :   return direct_optab_handler (optab, mode, opt_type) != CODE_FOR_nothing;
    4301              : }
    4302              : 
    4303              : /* Return true if OPTAB is supported for TYPES, where the first type
    4304              :    is the destination and the second type is the source.  Used for
    4305              :    convert optabs.  */
    4306              : 
    4307              : static bool
    4308        80557 : convert_optab_supported_p (convert_optab optab, tree_pair types,
    4309              :                            optimization_type opt_type)
    4310              : {
    4311        80557 :   return (convert_optab_handler (optab, TYPE_MODE (types.first),
    4312        80557 :                                  TYPE_MODE (types.second), opt_type)
    4313        80557 :           != CODE_FOR_nothing);
    4314              : }
    4315              : 
    4316              : /* Return true if load/store lanes optab OPTAB is supported for
    4317              :    array type TYPES.first when the optimization type is OPT_TYPE.  */
    4318              : 
    4319              : static bool
    4320            0 : multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
    4321              :                                 optimization_type opt_type)
    4322              : {
    4323            0 :   gcc_assert (TREE_CODE (types.first) == ARRAY_TYPE);
    4324            0 :   machine_mode imode = TYPE_MODE (types.first);
    4325            0 :   machine_mode vmode = TYPE_MODE (TREE_TYPE (types.first));
    4326            0 :   return (convert_optab_handler (optab, imode, vmode, opt_type)
    4327            0 :           != CODE_FOR_nothing);
    4328              : }
    4329              : 
    4330              : #define direct_unary_optab_supported_p direct_optab_supported_p
    4331              : #define direct_unary_convert_optab_supported_p convert_optab_supported_p
    4332              : #define direct_binary_optab_supported_p direct_optab_supported_p
    4333              : #define direct_ternary_optab_supported_p direct_optab_supported_p
    4334              : #define direct_cond_unary_optab_supported_p direct_optab_supported_p
    4335              : #define direct_cond_binary_optab_supported_p direct_optab_supported_p
    4336              : #define direct_cond_ternary_optab_supported_p direct_optab_supported_p
    4337              : #define direct_cond_len_unary_optab_supported_p direct_optab_supported_p
    4338              : #define direct_cond_len_binary_optab_supported_p direct_optab_supported_p
    4339              : #define direct_cond_len_ternary_optab_supported_p direct_optab_supported_p
    4340              : #define direct_crc_optab_supported_p convert_optab_supported_p
    4341              : #define direct_mask_load_optab_supported_p convert_optab_supported_p
    4342              : #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
    4343              : #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
    4344              : #define direct_gather_load_optab_supported_p convert_optab_supported_p
    4345              : #define direct_strided_load_optab_supported_p direct_optab_supported_p
    4346              : #define direct_len_load_optab_supported_p direct_optab_supported_p
    4347              : #define direct_mask_len_load_optab_supported_p convert_optab_supported_p
    4348              : #define direct_mask_store_optab_supported_p convert_optab_supported_p
    4349              : #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
    4350              : #define direct_mask_store_lanes_optab_supported_p multi_vector_optab_supported_p
    4351              : #define direct_vec_cond_mask_optab_supported_p convert_optab_supported_p
    4352              : #define direct_vec_cond_optab_supported_p convert_optab_supported_p
    4353              : #define direct_scatter_store_optab_supported_p convert_optab_supported_p
    4354              : #define direct_strided_store_optab_supported_p direct_optab_supported_p
    4355              : #define direct_len_store_optab_supported_p direct_optab_supported_p
    4356              : #define direct_mask_len_store_optab_supported_p convert_optab_supported_p
    4357              : #define direct_while_optab_supported_p convert_optab_supported_p
    4358              : #define direct_fold_extract_optab_supported_p direct_optab_supported_p
    4359              : #define direct_fold_len_extract_optab_supported_p direct_optab_supported_p
    4360              : #define direct_fold_left_optab_supported_p direct_optab_supported_p
    4361              : #define direct_mask_fold_left_optab_supported_p direct_optab_supported_p
    4362              : #define direct_mask_len_fold_left_optab_supported_p direct_optab_supported_p
    4363              : #define direct_check_ptrs_optab_supported_p direct_optab_supported_p
    4364              : #define direct_vec_set_optab_supported_p direct_optab_supported_p
    4365              : #define direct_vec_extract_optab_supported_p convert_optab_supported_p
    4366              : #define direct_reduc_sbool_optab_supported_p direct_optab_supported_p
    4367              : #define direct_select_vl_optab_supported_p convert_optab_supported_p
    4368              : 
    4369              : /* Return the optab used by internal function FN.  */
    4370              : 
    4371              : optab
    4372       210481 : direct_internal_fn_optab (internal_fn fn, tree_pair types)
    4373              : {
    4374       210481 :   switch (fn)
    4375              :     {
    4376              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
    4377              :     case IFN_##CODE: break;
    4378              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4379              :     case IFN_##CODE: return OPTAB##_optab;
    4380              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
    4381              :                                      UNSIGNED_OPTAB, TYPE)              \
    4382              :     case IFN_##CODE: return (TYPE_UNSIGNED (types.SELECTOR)             \
    4383              :                              ? UNSIGNED_OPTAB ## _optab                 \
    4384              :                              : SIGNED_OPTAB ## _optab);
    4385              : #include "internal-fn.def"
    4386              : 
    4387              :     case IFN_LAST:
    4388              :       break;
    4389              :     }
    4390            0 :   gcc_unreachable ();
    4391              : }
    4392              : 
    4393              : /* Return the optab used by internal function FN.  */
    4394              : 
    4395              : static optab
    4396      1149076 : direct_internal_fn_optab (internal_fn fn)
    4397              : {
    4398      1149076 :   switch (fn)
    4399              :     {
    4400              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
    4401              :     case IFN_##CODE: break;
    4402              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4403              :     case IFN_##CODE: return OPTAB##_optab;
    4404              : #include "internal-fn.def"
    4405              : 
    4406              :     case IFN_LAST:
    4407              :       break;
    4408              :     }
    4409            0 :   gcc_unreachable ();
    4410              : }
    4411              : 
    4412              : /* Return true if TYPE's mode has the same format as TYPE, and if there is
    4413              :    a 1:1 correspondence between the values that the mode can store and the
    4414              :    values that the type can store.  */
    4415              : 
    4416              : static bool
    4417      8322272 : type_strictly_matches_mode_p (const_tree type)
    4418              : {
    4419              :   /* The masked vector operations have both vector data operands and vector
    4420              :      boolean operands.  The vector data operands are expected to have a vector
    4421              :      mode,  but the vector boolean operands can be an integer mode rather than
    4422              :      a vector mode,  depending on how TARGET_VECTORIZE_GET_MASK_MODE is
    4423              :      defined.  PR116103.  */
    4424      1081266 :   if (VECTOR_BOOLEAN_TYPE_P (type)
    4425       277320 :       && SCALAR_INT_MODE_P (TYPE_MODE (type))
    4426      8391218 :       && TYPE_PRECISION (TREE_TYPE (type)) == 1)
    4427              :     return true;
    4428              : 
    4429      8253327 :   if (VECTOR_TYPE_P (type))
    4430      1012321 :     return VECTOR_MODE_P (TYPE_MODE (type));
    4431              : 
    4432      7241006 :   if (INTEGRAL_TYPE_P (type))
    4433      6836630 :     return type_has_mode_precision_p (type);
    4434              : 
    4435       404376 :   if (SCALAR_FLOAT_TYPE_P (type) || COMPLEX_FLOAT_TYPE_P (type))
    4436              :     return true;
    4437              : 
    4438              :   return false;
    4439              : }
    4440              : 
    4441              : /* Returns true if both types of TYPE_PAIR strictly match their modes,
    4442              :    else returns false.  */
    4443              : 
    4444              : static bool
    4445      4226230 : type_pair_strictly_matches_mode_p (tree_pair type_pair)
    4446              : {
    4447      4226230 :   return type_strictly_matches_mode_p (type_pair.first)
    4448      4226230 :     && type_strictly_matches_mode_p (type_pair.second);
    4449              : }
    4450              : 
    4451              : /* Return true if FN is supported for the types in TYPES when the
    4452              :    optimization type is OPT_TYPE.  The types are those associated with
    4453              :    the "type0" and "type1" fields of FN's direct_internal_fn_info
    4454              :    structure.  */
    4455              : 
    4456              : bool
    4457      4226230 : direct_internal_fn_supported_p (internal_fn fn, tree_pair types,
    4458              :                                 optimization_type opt_type)
    4459              : {
    4460      4226230 :   if (!type_pair_strictly_matches_mode_p (types))
    4461              :     return false;
    4462              : 
    4463      4096042 :   switch (fn)
    4464              :     {
    4465              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
    4466              :     case IFN_##CODE: break;
    4467              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4468              :     case IFN_##CODE: \
    4469              :       return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \
    4470              :                                                 opt_type);
    4471              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
    4472              :                                      UNSIGNED_OPTAB, TYPE)              \
    4473              :     case IFN_##CODE:                                                    \
    4474              :       {                                                                 \
    4475              :         optab which_optab = (TYPE_UNSIGNED (types.SELECTOR)             \
    4476              :                              ? UNSIGNED_OPTAB ## _optab                 \
    4477              :                              : SIGNED_OPTAB ## _optab);                 \
    4478              :         return direct_##TYPE##_optab_supported_p (which_optab, types,   \
    4479              :                                                   opt_type);            \
    4480              :       }
    4481              : #include "internal-fn.def"
    4482              : 
    4483              :     case IFN_LAST:
    4484              :       break;
    4485              :     }
    4486            0 :   gcc_unreachable ();
    4487              : }
    4488              : 
    4489              : /* Return true if FN is supported for type TYPE when the optimization
    4490              :    type is OPT_TYPE.  The caller knows that the "type0" and "type1"
    4491              :    fields of FN's direct_internal_fn_info structure are the same.  */
    4492              : 
    4493              : bool
    4494      4070365 : direct_internal_fn_supported_p (internal_fn fn, tree type,
    4495              :                                 optimization_type opt_type)
    4496              : {
    4497      4070365 :   const direct_internal_fn_info &info = direct_internal_fn (fn);
    4498      4070365 :   gcc_checking_assert (info.type0 == info.type1);
    4499      4070365 :   return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
    4500              : }
    4501              : 
    4502              : /* Return true if the STMT is supported when the optimization type is OPT_TYPE,
    4503              :    given that STMT is a call to a direct internal function.  */
    4504              : 
    4505              : bool
    4506          384 : direct_internal_fn_supported_p (gcall *stmt, optimization_type opt_type)
    4507              : {
    4508          384 :   internal_fn fn = gimple_call_internal_fn (stmt);
    4509          384 :   tree_pair types = direct_internal_fn_types (fn, stmt);
    4510          384 :   return direct_internal_fn_supported_p (fn, types, opt_type);
    4511              : }
    4512              : 
    4513              : /* Return true if FN is a binary operation and if FN is commutative.  */
    4514              : 
    4515              : bool
    4516     32786149 : commutative_binary_fn_p (internal_fn fn)
    4517              : {
    4518     32786149 :   switch (fn)
    4519              :     {
    4520              :     case IFN_AVG_FLOOR:
    4521              :     case IFN_AVG_CEIL:
    4522              :     case IFN_MULH:
    4523              :     case IFN_MULHS:
    4524              :     case IFN_MULHRS:
    4525              :     case IFN_FMIN:
    4526              :     case IFN_FMAX:
    4527              :     case IFN_COMPLEX_MUL:
    4528              :     case IFN_UBSAN_CHECK_ADD:
    4529              :     case IFN_UBSAN_CHECK_MUL:
    4530              :     case IFN_ADD_OVERFLOW:
    4531              :     case IFN_MUL_OVERFLOW:
    4532              :     case IFN_SAT_ADD:
    4533              :     case IFN_SAT_MUL:
    4534              :     case IFN_VEC_WIDEN_PLUS:
    4535              :     case IFN_VEC_WIDEN_PLUS_LO:
    4536              :     case IFN_VEC_WIDEN_PLUS_HI:
    4537              :     case IFN_VEC_WIDEN_PLUS_EVEN:
    4538              :     case IFN_VEC_WIDEN_PLUS_ODD:
    4539              :       return true;
    4540              : 
    4541     31894442 :     default:
    4542     31894442 :       return false;
    4543              :     }
    4544              : }
    4545              : 
    4546              : /* Return true if FN is a ternary operation and if its first two arguments
    4547              :    are commutative.  */
    4548              : 
    4549              : bool
    4550     26598039 : commutative_ternary_fn_p (internal_fn fn)
    4551              : {
    4552     26598039 :   switch (fn)
    4553              :     {
    4554              :     case IFN_FMA:
    4555              :     case IFN_FMS:
    4556              :     case IFN_FNMA:
    4557              :     case IFN_FNMS:
    4558              :     case IFN_UADDC:
    4559              :       return true;
    4560              : 
    4561     26469961 :     default:
    4562     26469961 :       return false;
    4563              :     }
    4564              : }
    4565              : 
    4566              : /* Return true if FN is an associative binary operation.  */
    4567              : 
    4568              : bool
    4569           52 : associative_binary_fn_p (internal_fn fn)
    4570              : {
    4571           52 :   switch (fn)
    4572              :     {
    4573              :     case IFN_FMIN:
    4574              :     case IFN_FMAX:
    4575              :       return true;
    4576              : 
    4577            0 :     default:
    4578            0 :       return false;
    4579              :     }
    4580              : }
    4581              : 
    4582              : /* If FN is commutative in two consecutive arguments, return the
    4583              :    index of the first, otherwise return -1.  */
    4584              : 
    4585              : int
    4586     26924676 : first_commutative_argument (internal_fn fn)
    4587              : {
    4588     26924676 :   switch (fn)
    4589              :     {
    4590              :     case IFN_COND_ADD:
    4591              :     case IFN_COND_MUL:
    4592              :     case IFN_COND_MIN:
    4593              :     case IFN_COND_MAX:
    4594              :     case IFN_COND_FMIN:
    4595              :     case IFN_COND_FMAX:
    4596              :     case IFN_COND_AND:
    4597              :     case IFN_COND_IOR:
    4598              :     case IFN_COND_XOR:
    4599              :     case IFN_COND_FMA:
    4600              :     case IFN_COND_FMS:
    4601              :     case IFN_COND_FNMA:
    4602              :     case IFN_COND_FNMS:
    4603              :     case IFN_COND_LEN_ADD:
    4604              :     case IFN_COND_LEN_MUL:
    4605              :     case IFN_COND_LEN_MIN:
    4606              :     case IFN_COND_LEN_MAX:
    4607              :     case IFN_COND_LEN_FMIN:
    4608              :     case IFN_COND_LEN_FMAX:
    4609              :     case IFN_COND_LEN_AND:
    4610              :     case IFN_COND_LEN_IOR:
    4611              :     case IFN_COND_LEN_XOR:
    4612              :     case IFN_COND_LEN_FMA:
    4613              :     case IFN_COND_LEN_FMS:
    4614              :     case IFN_COND_LEN_FNMA:
    4615              :     case IFN_COND_LEN_FNMS:
    4616              :       return 1;
    4617              : 
    4618     26906222 :     default:
    4619     26906222 :       if (commutative_binary_fn_p (fn)
    4620     26906222 :           || commutative_ternary_fn_p (fn))
    4621       436285 :         return 0;
    4622              :       return -1;
    4623              :     }
    4624              : }
    4625              : 
    4626              : /* Return true if this CODE describes an internal_fn that returns a vector with
    4627              :    elements twice as wide as the element size of the input vectors.  */
    4628              : 
    4629              : bool
    4630      1786723 : widening_fn_p (code_helper code)
    4631              : {
    4632      1786723 :   if (!code.is_fn_code ())
    4633              :     return false;
    4634              : 
    4635       161553 :   if (!internal_fn_p ((combined_fn) code))
    4636              :     return false;
    4637              : 
    4638       161553 :   internal_fn fn = as_internal_fn ((combined_fn) code);
    4639       161553 :   switch (fn)
    4640              :     {
    4641              :     #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
    4642              :     case IFN_##NAME:                                              \
    4643              :     case IFN_##NAME##_HI:                                         \
    4644              :     case IFN_##NAME##_LO:                                         \
    4645              :     case IFN_##NAME##_EVEN:                                       \
    4646              :     case IFN_##NAME##_ODD:                                        \
    4647              :       return true;
    4648              :     #include "internal-fn.def"
    4649              : 
    4650              :     default:
    4651              :       return false;
    4652              :     }
    4653              : }
    4654              : 
    4655              : /* Return true if this CODE describes an internal_fn that returns a vector with
    4656              :    elements twice as wide as the element size of the input vectors and operates
    4657              :    on even/odd parts of the input.  */
    4658              : 
    4659              : bool
    4660        17144 : widening_evenodd_fn_p (code_helper code)
    4661              : {
    4662        17144 :   if (!code.is_fn_code ())
    4663              :     return false;
    4664              : 
    4665            0 :   if (!internal_fn_p ((combined_fn) code))
    4666              :     return false;
    4667              : 
    4668            0 :   internal_fn fn = as_internal_fn ((combined_fn) code);
    4669            0 :   switch (fn)
    4670              :     {
    4671              :     #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
    4672              :     case IFN_##NAME##_EVEN:                                       \
    4673              :     case IFN_##NAME##_ODD:                                        \
    4674              :       return true;
    4675              :     #include "internal-fn.def"
    4676              : 
    4677              :     default:
    4678              :       return false;
    4679              :     }
    4680              : }
    4681              : 
    4682              : /* Return true if IFN_SET_EDOM is supported.  */
    4683              : 
    4684              : bool
    4685          139 : set_edom_supported_p (void)
    4686              : {
    4687              : #ifdef TARGET_EDOM
    4688              :   return true;
    4689              : #else
    4690          139 :   return false;
    4691              : #endif
    4692              : }
    4693              : 
    4694              : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
    4695              :   static void                                           \
    4696              :   expand_##CODE (internal_fn fn, gcall *stmt)           \
    4697              :   {                                                     \
    4698              :     expand_##TYPE##_optab_fn (fn, stmt, OPTAB##_optab); \
    4699              :   }
    4700              : #define DEF_INTERNAL_INT_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
    4701              : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
    4702              :                                      UNSIGNED_OPTAB, TYPE)              \
    4703              :   static void                                                           \
    4704              :   expand_##CODE (internal_fn fn, gcall *stmt)                           \
    4705              :   {                                                                     \
    4706              :     tree_pair types = direct_internal_fn_types (fn, stmt);              \
    4707              :     optab which_optab = direct_internal_fn_optab (fn, types);           \
    4708              :     expand_##TYPE##_optab_fn (fn, stmt, which_optab);                   \
    4709              :   }
    4710              : #include "internal-fn.def"
    4711              : 
    4712              : /* Routines to expand each internal function, indexed by function number.
    4713              :    Each routine has the prototype:
    4714              : 
    4715              :        expand_<NAME> (gcall *stmt)
    4716              : 
    4717              :    where STMT is the statement that performs the call. */
    4718              : static void (*const internal_fn_expanders[]) (internal_fn, gcall *) = {
    4719              : 
    4720              : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) expand_##CODE,
    4721              : #include "internal-fn.def"
    4722              :   0
    4723              : };
    4724              : 
    4725              : /* Invoke T(CODE, SUFFIX) for each conditional function IFN_COND_##SUFFIX
    4726              :    that maps to a tree code CODE.  There is also an IFN_COND_LEN_##SUFFIX
    4727              :    for each such IFN_COND_##SUFFIX.  */
    4728              : #define FOR_EACH_CODE_MAPPING(T) \
    4729              :   T (PLUS_EXPR, ADD) \
    4730              :   T (MINUS_EXPR, SUB) \
    4731              :   T (MULT_EXPR, MUL) \
    4732              :   T (TRUNC_DIV_EXPR, DIV) \
    4733              :   T (TRUNC_MOD_EXPR, MOD) \
    4734              :   T (RDIV_EXPR, RDIV) \
    4735              :   T (MIN_EXPR, MIN) \
    4736              :   T (MAX_EXPR, MAX) \
    4737              :   T (BIT_AND_EXPR, AND) \
    4738              :   T (BIT_IOR_EXPR, IOR) \
    4739              :   T (BIT_XOR_EXPR, XOR) \
    4740              :   T (LSHIFT_EXPR, SHL) \
    4741              :   T (RSHIFT_EXPR, SHR) \
    4742              :   T (NEGATE_EXPR, NEG)
    4743              : 
    4744              : /* Return a function that only performs CODE when a certain condition is met
    4745              :    and that uses a given fallback value otherwise.  For example, if CODE is
    4746              :    a binary operation associated with conditional function FN:
    4747              : 
    4748              :      LHS = FN (COND, A, B, ELSE)
    4749              : 
    4750              :    is equivalent to the C expression:
    4751              : 
    4752              :      LHS = COND ? A CODE B : ELSE;
    4753              : 
    4754              :    operating elementwise if the operands are vectors.
    4755              : 
    4756              :    Return IFN_LAST if no such function exists.  */
    4757              : 
    4758              : internal_fn
    4759       556802 : get_conditional_internal_fn (tree_code code)
    4760              : {
    4761       556802 :   switch (code)
    4762              :     {
    4763              : #define CASE(CODE, IFN) case CODE: return IFN_COND_##IFN;
    4764              :       FOR_EACH_CODE_MAPPING(CASE)
    4765              : #undef CASE
    4766              :     default:
    4767              :       return IFN_LAST;
    4768              :     }
    4769              : }
    4770              : 
    4771              : /* If IFN implements the conditional form of a tree code, return that
    4772              :    tree code, otherwise return ERROR_MARK.  */
    4773              : 
    4774              : tree_code
    4775      3188308 : conditional_internal_fn_code (internal_fn ifn)
    4776              : {
    4777      3188308 :   switch (ifn)
    4778              :     {
    4779              : #define CASE(CODE, IFN)                                                        \
    4780              :   case IFN_COND_##IFN:                                                         \
    4781              :   case IFN_COND_LEN_##IFN:                                                     \
    4782              :     return CODE;
    4783              :       FOR_EACH_CODE_MAPPING (CASE)
    4784              : #undef CASE
    4785              :       default:
    4786              :         return ERROR_MARK;
    4787              :     }
    4788              : }
    4789              : 
    4790              : /* Like get_conditional_internal_fn, but return a function that
    4791              :    additionally restricts the operation to the leading elements
    4792              :    of a vector.  The number of elements to process is given by a length
    4793              :    and bias pair, as for IFN_LOAD_LEN.  The values of the remaining
    4794              :    elements are taken from the fallback ("else") argument.
    4795              : 
    4796              :    For example, if CODE is a binary operation associated with FN:
    4797              : 
    4798              :      LHS = FN (COND, A, B, ELSE, LEN, BIAS)
    4799              : 
    4800              :    is equivalent to the C code:
    4801              : 
    4802              :      for (int i = 0; i < NUNITS; i++)
    4803              :       {
    4804              :         if (i < LEN + BIAS && COND[i])
    4805              :           LHS[i] = A[i] CODE B[i];
    4806              :         else
    4807              :           LHS[i] = ELSE[i];
    4808              :       }
    4809              : */
    4810              : 
    4811              : internal_fn
    4812       534241 : get_conditional_len_internal_fn (tree_code code)
    4813              : {
    4814       534241 :   switch (code)
    4815              :     {
    4816              : #define CASE(CODE, IFN) case CODE: return IFN_COND_LEN_##IFN;
    4817              :       FOR_EACH_CODE_MAPPING(CASE)
    4818              : #undef CASE
    4819              :     default:
    4820              :       return IFN_LAST;
    4821              :     }
    4822              : }
    4823              : 
    4824              : /* Invoke T(IFN) for each internal function IFN that also has an
    4825              :    IFN_COND_* form.  */
    4826              : #define FOR_EACH_COND_FN_PAIR(T) \
    4827              :   T (FMAX) \
    4828              :   T (FMIN) \
    4829              :   T (FMA) \
    4830              :   T (FMS) \
    4831              :   T (FNMA) \
    4832              :   T (FNMS) \
    4833              :   T (SQRT) \
    4834              :   T (ROUND) \
    4835              :   T (FLOOR) \
    4836              :   T (RINT) \
    4837              :   T (CEIL)
    4838              : 
    4839              : /* Return a function that only performs internal function FN when a
    4840              :    certain condition is met and that uses a given fallback value otherwise.
    4841              :    In other words, the returned function FN' is such that:
    4842              : 
    4843              :      LHS = FN' (COND, A1, ... An, ELSE)
    4844              : 
    4845              :    is equivalent to the C expression:
    4846              : 
    4847              :      LHS = COND ? FN (A1, ..., An) : ELSE;
    4848              : 
    4849              :    operating elementwise if the operands are vectors.
    4850              : 
    4851              :    Return IFN_LAST if no such function exists.  */
    4852              : 
    4853              : internal_fn
    4854         8488 : get_conditional_internal_fn (internal_fn fn)
    4855              : {
    4856         8488 :   switch (fn)
    4857              :     {
    4858              : #define CASE(NAME) case IFN_##NAME: return IFN_COND_##NAME;
    4859         1850 :       FOR_EACH_COND_FN_PAIR(CASE)
    4860              : #undef CASE
    4861         6637 :     default:
    4862         6637 :       return IFN_LAST;
    4863              :     }
    4864              : }
    4865              : 
    4866              : /* If there exists an internal function like IFN that operates on vectors,
    4867              :    but with additional length and bias parameters, return the internal_fn
    4868              :    for that function, otherwise return IFN_LAST.  */
    4869              : internal_fn
    4870         9985 : get_len_internal_fn (internal_fn fn)
    4871              : {
    4872         9985 :   switch (fn)
    4873              :     {
    4874              : #define DEF_INTERNAL_COND_FN(NAME, ...)                                        \
    4875              :   case IFN_COND_##NAME:                                                        \
    4876              :     return IFN_COND_LEN_##NAME;
    4877              : #define DEF_INTERNAL_SIGNED_COND_FN(NAME, ...)                                 \
    4878              :   case IFN_COND_##NAME:                                                        \
    4879              :     return IFN_COND_LEN_##NAME;
    4880              : #include "internal-fn.def"
    4881         6599 :     default:
    4882         6599 :       break;
    4883              :     }
    4884              : 
    4885         6599 :   switch (fn)
    4886              :     {
    4887              :     case IFN_MASK_LOAD:
    4888              :       return IFN_MASK_LEN_LOAD;
    4889              :     case IFN_MASK_LOAD_LANES:
    4890              :       return IFN_MASK_LEN_LOAD_LANES;
    4891              :     case IFN_MASK_GATHER_LOAD:
    4892              :       return IFN_MASK_LEN_GATHER_LOAD;
    4893              :     default:
    4894              :       return IFN_LAST;
    4895              :     }
    4896              : }
    4897              : 
    4898              : /* If IFN implements the conditional form of an unconditional internal
    4899              :    function, return that unconditional function, otherwise return IFN_LAST.  */
    4900              : 
    4901              : internal_fn
    4902      3142371 : get_unconditional_internal_fn (internal_fn ifn)
    4903              : {
    4904      3142371 :   switch (ifn)
    4905              :     {
    4906              : #define CASE(NAME)                                                             \
    4907              :     case IFN_COND_##NAME:                                                      \
    4908              :     case IFN_COND_LEN_##NAME:                                                  \
    4909              :       return IFN_##NAME;
    4910              : FOR_EACH_COND_FN_PAIR (CASE)
    4911              : #undef CASE
    4912              :     default:
    4913              :       return IFN_LAST;
    4914              :     }
    4915              : }
    4916              : 
    4917              : /* Return true if STMT can be interpreted as a conditional tree code
    4918              :    operation of the form:
    4919              : 
    4920              :      LHS = COND ? OP (RHS1, ...) : ELSE;
    4921              : 
    4922              :    operating elementwise if the operands are vectors.  This includes
    4923              :    the case of an all-true COND, so that the operation always happens.
    4924              : 
    4925              :    There is an alternative approach to interpret the STMT when the operands
    4926              :    are vectors which is the operation predicated by both conditional mask
    4927              :    and loop control length, the equivalent C code:
    4928              : 
    4929              :      for (int i = 0; i < NUNTIS; i++)
    4930              :       {
    4931              :         if (i < LEN + BIAS && COND[i])
    4932              :           LHS[i] = A[i] CODE B[i];
    4933              :         else
    4934              :           LHS[i] = ELSE[i];
    4935              :       }
    4936              : 
    4937              :    When returning true, set:
    4938              : 
    4939              :    - *COND_OUT to the condition COND, or to NULL_TREE if the condition
    4940              :      is known to be all-true
    4941              :    - *CODE_OUT to the tree code
    4942              :    - OPS[I] to operand I of *CODE_OUT
    4943              :    - *ELSE_OUT to the fallback value ELSE, or to NULL_TREE if the
    4944              :      condition is known to be all true.
    4945              :    - *LEN to the len argument if it COND_LEN_* operations or to NULL_TREE.
    4946              :    - *BIAS to the bias argument if it COND_LEN_* operations or to NULL_TREE.  */
    4947              : 
    4948              : bool
    4949        40465 : can_interpret_as_conditional_op_p (gimple *stmt, tree *cond_out,
    4950              :                                    tree_code *code_out,
    4951              :                                    tree (&ops)[3], tree *else_out,
    4952              :                                    tree *len, tree *bias)
    4953              : {
    4954        40465 :   *len = NULL_TREE;
    4955        40465 :   *bias = NULL_TREE;
    4956        40465 :   if (gassign *assign = dyn_cast <gassign *> (stmt))
    4957              :     {
    4958        37685 :       *cond_out = NULL_TREE;
    4959        37685 :       *code_out = gimple_assign_rhs_code (assign);
    4960        37685 :       ops[0] = gimple_assign_rhs1 (assign);
    4961        37685 :       ops[1] = gimple_assign_rhs2 (assign);
    4962        37685 :       ops[2] = gimple_assign_rhs3 (assign);
    4963        37685 :       *else_out = NULL_TREE;
    4964        37685 :       return true;
    4965              :     }
    4966         2780 :   if (gcall *call = dyn_cast <gcall *> (stmt))
    4967         2205 :     if (gimple_call_internal_p (call))
    4968              :       {
    4969         2169 :         internal_fn ifn = gimple_call_internal_fn (call);
    4970         2169 :         tree_code code = conditional_internal_fn_code (ifn);
    4971         2169 :         int len_index = internal_fn_len_index (ifn);
    4972         2169 :         int cond_nargs = len_index >= 0 ? 4 : 2;
    4973         2169 :         if (code != ERROR_MARK)
    4974              :           {
    4975          216 :             *cond_out = gimple_call_arg (call, 0);
    4976          216 :             *code_out = code;
    4977          216 :             unsigned int nops = gimple_call_num_args (call) - cond_nargs;
    4978          864 :             for (unsigned int i = 0; i < 3; ++i)
    4979          648 :               ops[i] = i < nops ? gimple_call_arg (call, i + 1) : NULL_TREE;
    4980          216 :             *else_out = gimple_call_arg (call, nops + 1);
    4981          216 :             if (len_index < 0)
    4982              :               {
    4983          216 :                 if (integer_truep (*cond_out))
    4984              :                   {
    4985            0 :                     *cond_out = NULL_TREE;
    4986            0 :                     *else_out = NULL_TREE;
    4987              :                   }
    4988              :               }
    4989              :             else
    4990              :               {
    4991            0 :                 *len = gimple_call_arg (call, len_index);
    4992            0 :                 *bias = gimple_call_arg (call, len_index + 1);
    4993              :               }
    4994          216 :             return true;
    4995              :           }
    4996              :       }
    4997              :   return false;
    4998              : }
    4999              : 
    5000              : /* Return true if IFN is some form of load from memory.  */
    5001              : 
    5002              : bool
    5003      1190611 : internal_load_fn_p (internal_fn fn)
    5004              : {
    5005      1190611 :   switch (fn)
    5006              :     {
    5007              :     case IFN_MASK_LOAD:
    5008              :     case IFN_LOAD_LANES:
    5009              :     case IFN_MASK_LOAD_LANES:
    5010              :     case IFN_MASK_LEN_LOAD_LANES:
    5011              :     case IFN_GATHER_LOAD:
    5012              :     case IFN_MASK_GATHER_LOAD:
    5013              :     case IFN_MASK_LEN_GATHER_LOAD:
    5014              :     case IFN_LEN_LOAD:
    5015              :     case IFN_MASK_LEN_LOAD:
    5016              :       return true;
    5017              : 
    5018       273825 :     default:
    5019       273825 :       return false;
    5020              :     }
    5021              : }
    5022              : 
    5023              : /* Return true if IFN is some form of store to memory.  */
    5024              : 
    5025              : bool
    5026       493556 : internal_store_fn_p (internal_fn fn)
    5027              : {
    5028       493556 :   switch (fn)
    5029              :     {
    5030              :     case IFN_MASK_STORE:
    5031              :     case IFN_STORE_LANES:
    5032              :     case IFN_MASK_STORE_LANES:
    5033              :     case IFN_MASK_LEN_STORE_LANES:
    5034              :     case IFN_SCATTER_STORE:
    5035              :     case IFN_MASK_SCATTER_STORE:
    5036              :     case IFN_MASK_LEN_SCATTER_STORE:
    5037              :     case IFN_LEN_STORE:
    5038              :     case IFN_MASK_LEN_STORE:
    5039              :       return true;
    5040              : 
    5041       482983 :     default:
    5042       482983 :       return false;
    5043              :     }
    5044              : }
    5045              : 
    5046              : /* Return true if IFN is some form of gather load or scatter store.  */
    5047              : 
    5048              : bool
    5049        40189 : internal_gather_scatter_fn_p (internal_fn fn)
    5050              : {
    5051        40189 :   switch (fn)
    5052              :     {
    5053              :     case IFN_GATHER_LOAD:
    5054              :     case IFN_MASK_GATHER_LOAD:
    5055              :     case IFN_MASK_LEN_GATHER_LOAD:
    5056              :     case IFN_SCATTER_STORE:
    5057              :     case IFN_MASK_SCATTER_STORE:
    5058              :     case IFN_MASK_LEN_SCATTER_STORE:
    5059              :       return true;
    5060              : 
    5061        40189 :     default:
    5062        40189 :       return false;
    5063              :     }
    5064              : }
    5065              : 
    5066              : /* If FN takes a vector len argument, return the index of that argument,
    5067              :    otherwise return -1.  */
    5068              : 
    5069              : int
    5070      3037050 : internal_fn_len_index (internal_fn fn)
    5071              : {
    5072      3037050 :   switch (fn)
    5073              :     {
    5074              :     case IFN_LEN_LOAD:
    5075              :       return 3;
    5076              :     case IFN_LEN_STORE:
    5077              :       return 2;
    5078              : 
    5079              :     case IFN_MASK_LEN_SCATTER_STORE:
    5080              :       return 6;
    5081              : 
    5082              :     case IFN_MASK_LEN_STRIDED_LOAD:
    5083              :       return 5;
    5084              : 
    5085              :     case IFN_MASK_LEN_GATHER_LOAD:
    5086              :       return 7;
    5087              : 
    5088              :     case IFN_COND_LEN_FMA:
    5089              :     case IFN_COND_LEN_FMS:
    5090              :     case IFN_COND_LEN_FNMA:
    5091              :     case IFN_COND_LEN_FNMS:
    5092              :       return 5;
    5093              : 
    5094              :     case IFN_COND_LEN_ADD:
    5095              :     case IFN_COND_LEN_SUB:
    5096              :     case IFN_COND_LEN_MUL:
    5097              :     case IFN_COND_LEN_DIV:
    5098              :     case IFN_COND_LEN_MOD:
    5099              :     case IFN_COND_LEN_RDIV:
    5100              :     case IFN_COND_LEN_MIN:
    5101              :     case IFN_COND_LEN_MAX:
    5102              :     case IFN_COND_LEN_FMIN:
    5103              :     case IFN_COND_LEN_FMAX:
    5104              :     case IFN_COND_LEN_AND:
    5105              :     case IFN_COND_LEN_IOR:
    5106              :     case IFN_COND_LEN_XOR:
    5107              :     case IFN_COND_LEN_SHL:
    5108              :     case IFN_COND_LEN_SHR:
    5109              :     case IFN_MASK_LEN_STRIDED_STORE:
    5110              :       return 4;
    5111              : 
    5112              :     case IFN_COND_LEN_NEG:
    5113              :     case IFN_MASK_LEN_STORE:
    5114              :     case IFN_MASK_LEN_STORE_LANES:
    5115              :     case IFN_VCOND_MASK_LEN:
    5116              :       return 3;
    5117              : 
    5118              :     case IFN_MASK_LEN_LOAD:
    5119              :     case IFN_MASK_LEN_LOAD_LANES:
    5120              :       return 4;
    5121              : 
    5122              :     default:
    5123              :       return -1;
    5124              :     }
    5125              : }
    5126              : 
    5127              : /* If FN is an IFN_COND_* or IFN_COND_LEN_* function, return the index of the
    5128              :    argument that is used when the condition is false.  Return -1 otherwise.  */
    5129              : 
    5130              : int
    5131        62838 : internal_fn_else_index (internal_fn fn)
    5132              : {
    5133        62838 :   switch (fn)
    5134              :     {
    5135              :     case IFN_COND_NEG:
    5136              :     case IFN_COND_NOT:
    5137              :     case IFN_COND_SQRT:
    5138              :     case IFN_COND_CEIL:
    5139              :     case IFN_COND_FLOOR:
    5140              :     case IFN_COND_ROUND:
    5141              :     case IFN_COND_RINT:
    5142              :     case IFN_COND_LEN_NEG:
    5143              :     case IFN_COND_LEN_NOT:
    5144              :     case IFN_COND_LEN_SQRT:
    5145              :     case IFN_COND_LEN_CEIL:
    5146              :     case IFN_COND_LEN_FLOOR:
    5147              :     case IFN_COND_LEN_ROUND:
    5148              :     case IFN_COND_LEN_RINT:
    5149              :       return 2;
    5150              : 
    5151              :     case IFN_LEN_LOAD:
    5152              :       return 2;
    5153              : 
    5154              :     case IFN_COND_ADD:
    5155              :     case IFN_COND_SUB:
    5156              :     case IFN_COND_MUL:
    5157              :     case IFN_COND_DIV:
    5158              :     case IFN_COND_MOD:
    5159              :     case IFN_COND_MIN:
    5160              :     case IFN_COND_MAX:
    5161              :     case IFN_COND_FMIN:
    5162              :     case IFN_COND_FMAX:
    5163              :     case IFN_COND_AND:
    5164              :     case IFN_COND_IOR:
    5165              :     case IFN_COND_XOR:
    5166              :     case IFN_COND_SHL:
    5167              :     case IFN_COND_SHR:
    5168              :     case IFN_COND_LEN_ADD:
    5169              :     case IFN_COND_LEN_SUB:
    5170              :     case IFN_COND_LEN_MUL:
    5171              :     case IFN_COND_LEN_DIV:
    5172              :     case IFN_COND_LEN_MOD:
    5173              :     case IFN_COND_LEN_MIN:
    5174              :     case IFN_COND_LEN_MAX:
    5175              :     case IFN_COND_LEN_FMIN:
    5176              :     case IFN_COND_LEN_FMAX:
    5177              :     case IFN_COND_LEN_AND:
    5178              :     case IFN_COND_LEN_IOR:
    5179              :     case IFN_COND_LEN_XOR:
    5180              :     case IFN_COND_LEN_SHL:
    5181              :     case IFN_COND_LEN_SHR:
    5182              :       return 3;
    5183              : 
    5184              :     case IFN_MASK_LOAD:
    5185              :     case IFN_MASK_LEN_LOAD:
    5186              :     case IFN_MASK_LOAD_LANES:
    5187              :     case IFN_MASK_LEN_LOAD_LANES:
    5188              :       return 3;
    5189              : 
    5190              :     case IFN_COND_FMA:
    5191              :     case IFN_COND_FMS:
    5192              :     case IFN_COND_FNMA:
    5193              :     case IFN_COND_FNMS:
    5194              :     case IFN_COND_LEN_FMA:
    5195              :     case IFN_COND_LEN_FMS:
    5196              :     case IFN_COND_LEN_FNMA:
    5197              :     case IFN_COND_LEN_FNMS:
    5198              :     case IFN_MASK_LEN_STRIDED_LOAD:
    5199              :       return 4;
    5200              : 
    5201              :     case IFN_MASK_GATHER_LOAD:
    5202              :     case IFN_MASK_LEN_GATHER_LOAD:
    5203              :       return 6;
    5204              : 
    5205              :     default:
    5206              :       return -1;
    5207              :     }
    5208              : 
    5209              :   return -1;
    5210              : }
    5211              : 
    5212              : /* If FN takes a vector mask argument, return the index of that argument,
    5213              :    otherwise return -1.  */
    5214              : 
    5215              : int
    5216       192979 : internal_fn_mask_index (internal_fn fn)
    5217              : {
    5218       192979 :   switch (fn)
    5219              :     {
    5220              :     case IFN_MASK_LOAD:
    5221              :     case IFN_MASK_LOAD_LANES:
    5222              :     case IFN_MASK_LEN_LOAD_LANES:
    5223              :     case IFN_MASK_STORE:
    5224              :     case IFN_MASK_STORE_LANES:
    5225              :     case IFN_MASK_LEN_STORE_LANES:
    5226              :     case IFN_MASK_LEN_LOAD:
    5227              :     case IFN_MASK_LEN_STORE:
    5228              :       return 2;
    5229              : 
    5230            0 :     case IFN_MASK_LEN_STRIDED_LOAD:
    5231            0 :     case IFN_MASK_LEN_STRIDED_STORE:
    5232            0 :       return 3;
    5233              : 
    5234            0 :     case IFN_MASK_GATHER_LOAD:
    5235            0 :     case IFN_MASK_SCATTER_STORE:
    5236            0 :     case IFN_MASK_LEN_GATHER_LOAD:
    5237            0 :     case IFN_MASK_LEN_SCATTER_STORE:
    5238            0 :       return 5;
    5239              : 
    5240              :     case IFN_VCOND_MASK:
    5241              :     case IFN_VCOND_MASK_LEN:
    5242              :       return 0;
    5243              : 
    5244       154109 :     default:
    5245       154109 :       return (conditional_internal_fn_code (fn) != ERROR_MARK
    5246       154109 :               || get_unconditional_internal_fn (fn) != IFN_LAST ? 0 : -1);
    5247              :     }
    5248              : }
    5249              : 
    5250              : /* If FN takes a value that should be stored to memory, return the index
    5251              :    of that argument, otherwise return -1.  */
    5252              : 
    5253              : int
    5254        24747 : internal_fn_stored_value_index (internal_fn fn)
    5255              : {
    5256        24747 :   switch (fn)
    5257              :     {
    5258              :     case IFN_MASK_LEN_STRIDED_STORE:
    5259              :       return 2;
    5260              : 
    5261              :     case IFN_MASK_STORE:
    5262              :     case IFN_MASK_STORE_LANES:
    5263              :       return 3;
    5264              :     case IFN_SCATTER_STORE:
    5265              :     case IFN_MASK_SCATTER_STORE:
    5266              :     case IFN_MASK_LEN_SCATTER_STORE:
    5267              :       return 4;
    5268              : 
    5269              :     case IFN_LEN_STORE:
    5270              :       return 4;
    5271              : 
    5272              :     case IFN_MASK_LEN_STORE:
    5273              :     case IFN_MASK_LEN_STORE_LANES:
    5274              :       return 5;
    5275              : 
    5276              :     default:
    5277              :       return -1;
    5278              :     }
    5279              : }
    5280              : 
    5281              : /* If FN has an alias pointer return its index, otherwise return -1.  */
    5282              : 
    5283              : int
    5284            0 : internal_fn_alias_ptr_index (internal_fn fn)
    5285              : {
    5286            0 :   switch (fn)
    5287              :     {
    5288              :     case IFN_MASK_LOAD:
    5289              :     case IFN_MASK_LEN_LOAD:
    5290              :     case IFN_GATHER_LOAD:
    5291              :     case IFN_MASK_GATHER_LOAD:
    5292              :     case IFN_MASK_LEN_GATHER_LOAD:
    5293              :     case IFN_SCATTER_STORE:
    5294              :     case IFN_MASK_SCATTER_STORE:
    5295              :     case IFN_MASK_LEN_SCATTER_STORE:
    5296              :       return 1;
    5297              : 
    5298            0 :     default:
    5299            0 :       return -1;
    5300              :     }
    5301              : }
    5302              : 
    5303              : /* If FN is a gather/scatter return the index of its offset argument,
    5304              :    otherwise return -1.  */
    5305              : 
    5306              : int
    5307            0 : internal_fn_offset_index (internal_fn fn)
    5308              : {
    5309            0 :   if (!internal_gather_scatter_fn_p (fn))
    5310              :     return -1;
    5311              : 
    5312            0 :   switch (fn)
    5313              :     {
    5314              :     case IFN_GATHER_LOAD:
    5315              :     case IFN_MASK_GATHER_LOAD:
    5316              :     case IFN_MASK_LEN_GATHER_LOAD:
    5317              :     case IFN_SCATTER_STORE:
    5318              :     case IFN_MASK_SCATTER_STORE:
    5319              :     case IFN_MASK_LEN_SCATTER_STORE:
    5320              :       return 2;
    5321              : 
    5322              :     default:
    5323              :       return -1;
    5324              :     }
    5325              : }
    5326              : 
    5327              : /* If FN is a gather/scatter return the index of its scale argument,
    5328              :    otherwise return -1.  */
    5329              : 
    5330              : int
    5331            0 : internal_fn_scale_index (internal_fn fn)
    5332              : {
    5333            0 :   if (!internal_gather_scatter_fn_p (fn))
    5334              :     return -1;
    5335              : 
    5336            0 :   switch (fn)
    5337              :     {
    5338              :     case IFN_GATHER_LOAD:
    5339              :     case IFN_MASK_GATHER_LOAD:
    5340              :     case IFN_MASK_LEN_GATHER_LOAD:
    5341              :     case IFN_SCATTER_STORE:
    5342              :     case IFN_MASK_SCATTER_STORE:
    5343              :     case IFN_MASK_LEN_SCATTER_STORE:
    5344              :       return 3;
    5345              : 
    5346              :     default:
    5347              :       return -1;
    5348              :     }
    5349              : }
    5350              : 
    5351              : /* Store all supported else values for the optab referred to by ICODE
    5352              :    in ELSE_VALS.  The index of the else operand must be specified in
    5353              :    ELSE_INDEX.  */
    5354              : 
    5355              : void
    5356        45974 : get_supported_else_vals (enum insn_code icode, unsigned else_index,
    5357              :                          vec<int> &else_vals)
    5358              : {
    5359        45974 :   const struct insn_data_d *data = &insn_data[icode];
    5360        45974 :   if ((int) else_index >= data->n_operands || (int) else_index == -1)
    5361              :     return;
    5362              : 
    5363        45974 :   machine_mode else_mode = data->operand[else_index].mode;
    5364              : 
    5365        45974 :   else_vals.truncate (0);
    5366              : 
    5367              :   /* For now we only support else values of 0, -1, and "undefined".  */
    5368        45974 :   if (insn_operand_matches (icode, else_index, CONST0_RTX (else_mode)))
    5369        45974 :     else_vals.safe_push (MASK_LOAD_ELSE_ZERO);
    5370              : 
    5371        45974 :   if (insn_operand_matches (icode, else_index, gen_rtx_SCRATCH (else_mode)))
    5372            0 :     else_vals.safe_push (MASK_LOAD_ELSE_UNDEFINED);
    5373              : 
    5374        45974 :   if (GET_MODE_CLASS (else_mode) == MODE_VECTOR_INT
    5375        45974 :       && insn_operand_matches (icode, else_index, CONSTM1_RTX (else_mode)))
    5376            0 :     else_vals.safe_push (MASK_LOAD_ELSE_M1);
    5377              : }
    5378              : 
    5379              : /* Return true if the else value ELSE_VAL (one of MASK_LOAD_ELSE_ZERO,
    5380              :    MASK_LOAD_ELSE_M1, and MASK_LOAD_ELSE_UNDEFINED) is valid fo the optab
    5381              :    referred to by ICODE.  The index of the else operand must be specified
    5382              :    in ELSE_INDEX.  */
    5383              : 
    5384              : bool
    5385            0 : supported_else_val_p (enum insn_code icode, unsigned else_index, int else_val)
    5386              : {
    5387            0 :   if (else_val != MASK_LOAD_ELSE_ZERO && else_val != MASK_LOAD_ELSE_M1
    5388            0 :       && else_val != MASK_LOAD_ELSE_UNDEFINED)
    5389            0 :     gcc_unreachable ();
    5390              : 
    5391            0 :   auto_vec<int> else_vals;
    5392            0 :   get_supported_else_vals (icode, else_index, else_vals);
    5393            0 :   return else_vals.contains (else_val);
    5394            0 : }
    5395              : 
    5396              : /* Return true if the target supports gather load or scatter store function
    5397              :    IFN.  For loads, VECTOR_TYPE is the vector type of the load result,
    5398              :    while for stores it is the vector type of the stored data argument.
    5399              :    MEMORY_ELEMENT_TYPE is the type of the memory elements being loaded
    5400              :    or stored.  OFFSET_VECTOR_TYPE is the vector type that holds the
    5401              :    offset from the shared base address of each loaded or stored element.
    5402              :    SCALE is the amount by which these offsets should be multiplied
    5403              :    *after* they have been extended to address width.
    5404              :    If the target supports the gather load the supported else values
    5405              :    will be added to the vector ELSVAL points to if it is nonzero.  */
    5406              : 
    5407              : bool
    5408      4226612 : internal_gather_scatter_fn_supported_p (internal_fn ifn, tree vector_type,
    5409              :                                         tree memory_element_type,
    5410              :                                         tree offset_vector_type, int scale,
    5411              :                                         vec<int> *elsvals)
    5412              : {
    5413      4226612 :   if (!tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vector_type)),
    5414      4226612 :                            TYPE_SIZE (memory_element_type)))
    5415              :     return false;
    5416      4226612 :   if (maybe_ne (TYPE_VECTOR_SUBPARTS (vector_type),
    5417      8453224 :                 TYPE_VECTOR_SUBPARTS (offset_vector_type)))
    5418              :     return false;
    5419      1141270 :   optab optab = direct_internal_fn_optab (ifn);
    5420      1141270 :   insn_code icode = convert_optab_handler (optab, TYPE_MODE (vector_type),
    5421      1141270 :                                            TYPE_MODE (offset_vector_type));
    5422      1141270 :   int output_ops = internal_load_fn_p (ifn) ? 1 : 0;
    5423      1141270 :   bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (offset_vector_type));
    5424      1141270 :   bool ok = icode != CODE_FOR_nothing
    5425            0 :     && insn_operand_matches (icode, 2 + output_ops, GEN_INT (unsigned_p))
    5426      1141270 :     && insn_operand_matches (icode, 3 + output_ops, GEN_INT (scale));
    5427              : 
    5428      1141270 :   if (ok && elsvals)
    5429            0 :     get_supported_else_vals
    5430            0 :       (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
    5431              : 
    5432              :   return ok;
    5433              : }
    5434              : 
    5435              : /* Return true if the target supports a strided load/store function IFN
    5436              :    with VECTOR_TYPE.  If supported and ELSVALS is nonzero the supported else
    5437              :    values will be added to the vector ELSVALS points to.  */
    5438              : 
    5439              : bool
    5440         2540 : internal_strided_fn_supported_p (internal_fn ifn, tree vector_type,
    5441              :                                  vec<int> *elsvals)
    5442              : {
    5443         2540 :   machine_mode mode = TYPE_MODE (vector_type);
    5444         2540 :   optab optab = direct_internal_fn_optab (ifn);
    5445         2540 :   insn_code icode = direct_optab_handler (optab, mode);
    5446              : 
    5447         2540 :   bool ok = icode != CODE_FOR_nothing;
    5448              : 
    5449         2540 :   if (ok && elsvals)
    5450            0 :     get_supported_else_vals (icode, internal_fn_else_index (ifn), *elsvals);
    5451              : 
    5452         2540 :   return ok;
    5453              : }
    5454              : 
    5455              : /* Return true if the target supports IFN_CHECK_{RAW,WAR}_PTRS function IFN
    5456              :    for pointers of type TYPE when the accesses have LENGTH bytes and their
    5457              :    common byte alignment is ALIGN.  */
    5458              : 
    5459              : bool
    5460         5266 : internal_check_ptrs_fn_supported_p (internal_fn ifn, tree type,
    5461              :                                     poly_uint64 length, unsigned int align)
    5462              : {
    5463         5266 :   machine_mode mode = TYPE_MODE (type);
    5464         5266 :   optab optab = direct_internal_fn_optab (ifn);
    5465         5266 :   insn_code icode = direct_optab_handler (optab, mode);
    5466         5266 :   if (icode == CODE_FOR_nothing)
    5467              :     return false;
    5468            0 :   rtx length_rtx = immed_wide_int_const (length, mode);
    5469            0 :   return (insn_operand_matches (icode, 3, length_rtx)
    5470            0 :           && insn_operand_matches (icode, 4, GEN_INT (align)));
    5471              : }
    5472              : 
    5473              : /* Return the supported bias for IFN which is either IFN_{LEN_,MASK_LEN_,}LOAD
    5474              :    or IFN_{LEN_,MASK_LEN_,}STORE.  For now we only support the biases of 0 and
    5475              :    -1 (in case 0 is not an allowable length for {len_,mask_len_}load or
    5476              :    {len_,mask_len_}store). If none of the biases match what the backend
    5477              :    provides, return VECT_PARTIAL_BIAS_UNSUPPORTED.  */
    5478              : 
    5479              : signed char
    5480            0 : internal_len_load_store_bias (internal_fn ifn, machine_mode mode)
    5481              : {
    5482            0 :   optab optab = direct_internal_fn_optab (ifn);
    5483            0 :   insn_code icode = direct_optab_handler (optab, mode);
    5484            0 :   int bias_idx = internal_fn_len_index (ifn) + 1;
    5485              : 
    5486            0 :   if (icode == CODE_FOR_nothing)
    5487              :     {
    5488            0 :       machine_mode mask_mode;
    5489            0 :       if (!targetm.vectorize.get_mask_mode (mode).exists (&mask_mode))
    5490            0 :         return VECT_PARTIAL_BIAS_UNSUPPORTED;
    5491            0 :       if (ifn == IFN_LEN_LOAD)
    5492              :         {
    5493              :           /* Try MASK_LEN_LOAD.  */
    5494            0 :           optab = direct_internal_fn_optab (IFN_MASK_LEN_LOAD);
    5495            0 :           bias_idx = internal_fn_len_index (IFN_MASK_LEN_LOAD) + 1;
    5496              :         }
    5497              :       else
    5498              :         {
    5499              :           /* Try MASK_LEN_STORE.  */
    5500            0 :           optab = direct_internal_fn_optab (IFN_MASK_LEN_STORE);
    5501            0 :           bias_idx = internal_fn_len_index (IFN_MASK_LEN_STORE) + 1;
    5502              :         }
    5503            0 :       icode = convert_optab_handler (optab, mode, mask_mode);
    5504              :     }
    5505              : 
    5506            0 :   if (icode != CODE_FOR_nothing)
    5507              :     {
    5508              :       /* For now we only support biases of 0 or -1.  Try both of them.  */
    5509            0 :       if (insn_operand_matches (icode, bias_idx, GEN_INT (0)))
    5510              :         return 0;
    5511            0 :       if (insn_operand_matches (icode, bias_idx, GEN_INT (-1)))
    5512              :         return -1;
    5513              :     }
    5514              : 
    5515              :   return VECT_PARTIAL_BIAS_UNSUPPORTED;
    5516              : }
    5517              : 
    5518              : /* Expand STMT as though it were a call to internal function FN.  */
    5519              : 
    5520              : void
    5521       255244 : expand_internal_call (internal_fn fn, gcall *stmt)
    5522              : {
    5523       255244 :   internal_fn_expanders[fn] (fn, stmt);
    5524       255244 : }
    5525              : 
    5526              : /* Expand STMT, which is a call to internal function FN.  */
    5527              : 
    5528              : void
    5529       221013 : expand_internal_call (gcall *stmt)
    5530              : {
    5531       221013 :   expand_internal_call (gimple_call_internal_fn (stmt), stmt);
    5532       221013 : }
    5533              : 
    5534              : /* If TYPE is a vector type, return true if IFN is a direct internal
    5535              :    function that is supported for that type.  If TYPE is a scalar type,
    5536              :    return true if IFN is a direct internal function that is supported for
    5537              :    the target's preferred vector version of TYPE.  */
    5538              : 
    5539              : bool
    5540        14854 : vectorized_internal_fn_supported_p (internal_fn ifn, tree type)
    5541              : {
    5542        14854 :   if (VECTOR_MODE_P (TYPE_MODE (type)))
    5543         8603 :     return direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED);
    5544              : 
    5545         6251 :   scalar_mode smode;
    5546         6251 :   if (VECTOR_TYPE_P (type)
    5547         6251 :       || !is_a <scalar_mode> (TYPE_MODE (type), &smode))
    5548           11 :     return false;
    5549              : 
    5550         6240 :   machine_mode vmode = targetm.vectorize.preferred_simd_mode (smode);
    5551         6240 :   if (VECTOR_MODE_P (vmode))
    5552              :     {
    5553         6203 :       tree vectype = build_vector_type_for_mode (type, vmode);
    5554         6203 :       if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
    5555              :         return true;
    5556              :     }
    5557              : 
    5558         4230 :   auto_vector_modes vector_modes;
    5559         4230 :   targetm.vectorize.autovectorize_vector_modes (&vector_modes, true);
    5560        26394 :   for (machine_mode base_mode : vector_modes)
    5561        13704 :     if (related_vector_mode (base_mode, smode).exists (&vmode))
    5562              :       {
    5563        12054 :         tree vectype = build_vector_type_for_mode (type, vmode);
    5564        12054 :         if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
    5565              :           return true;
    5566              :       }
    5567              : 
    5568              :   return false;
    5569         4230 : }
    5570              : 
    5571              : void
    5572            0 : expand_SHUFFLEVECTOR (internal_fn, gcall *)
    5573              : {
    5574            0 :   gcc_unreachable ();
    5575              : }
    5576              : 
    5577              : void
    5578            0 : expand_PHI (internal_fn, gcall *)
    5579              : {
    5580            0 :   gcc_unreachable ();
    5581              : }
    5582              : 
    5583              : void
    5584          279 : expand_SPACESHIP (internal_fn, gcall *stmt)
    5585              : {
    5586          279 :   tree lhs = gimple_call_lhs (stmt);
    5587          279 :   tree rhs1 = gimple_call_arg (stmt, 0);
    5588          279 :   tree rhs2 = gimple_call_arg (stmt, 1);
    5589          279 :   tree rhs3 = gimple_call_arg (stmt, 2);
    5590          279 :   tree type = TREE_TYPE (rhs1);
    5591              : 
    5592          279 :   do_pending_stack_adjust ();
    5593              : 
    5594          279 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5595          279 :   rtx op1 = expand_normal (rhs1);
    5596          279 :   rtx op2 = expand_normal (rhs2);
    5597          279 :   rtx op3 = expand_normal (rhs3);
    5598              : 
    5599          279 :   class expand_operand ops[4];
    5600          279 :   create_call_lhs_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (lhs)));
    5601          279 :   create_input_operand (&ops[1], op1, TYPE_MODE (type));
    5602          279 :   create_input_operand (&ops[2], op2, TYPE_MODE (type));
    5603          279 :   create_input_operand (&ops[3], op3, TYPE_MODE (TREE_TYPE (rhs3)));
    5604          279 :   insn_code icode = optab_handler (spaceship_optab, TYPE_MODE (type));
    5605          279 :   expand_insn (icode, 4, ops);
    5606          279 :   assign_call_lhs (lhs, target, &ops[0]);
    5607          279 : }
    5608              : 
    5609              : void
    5610            0 : expand_ASSUME (internal_fn, gcall *)
    5611              : {
    5612            0 : }
    5613              : 
    5614              : void
    5615            0 : expand_MASK_CALL (internal_fn, gcall *)
    5616              : {
    5617              :   /* This IFN should only exist between ifcvt and vect passes.  */
    5618            0 :   gcc_unreachable ();
    5619              : }
    5620              : 
    5621              : void
    5622         1566 : expand_MULBITINT (internal_fn, gcall *stmt)
    5623              : {
    5624         1566 :   rtx_mode_t args[6];
    5625        10962 :   for (int i = 0; i < 6; i++)
    5626         9396 :     args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
    5627        18792 :                           (i & 1) ? SImode : ptr_mode);
    5628         1566 :   rtx fun = init_one_libfunc ("__mulbitint3");
    5629         1566 :   emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 6, args);
    5630         1566 : }
    5631              : 
    5632              : void
    5633          139 : expand_DIVMODBITINT (internal_fn, gcall *stmt)
    5634              : {
    5635          139 :   rtx_mode_t args[8];
    5636         1251 :   for (int i = 0; i < 8; i++)
    5637         1112 :     args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
    5638         2224 :                           (i & 1) ? SImode : ptr_mode);
    5639          139 :   rtx fun = init_one_libfunc ("__divmodbitint4");
    5640          139 :   emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 8, args);
    5641          139 : }
    5642              : 
    5643              : void
    5644          167 : expand_FLOATTOBITINT (internal_fn, gcall *stmt)
    5645              : {
    5646          167 :   machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_call_arg (stmt, 2)));
    5647          167 :   rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
    5648          167 :   rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
    5649          167 :   rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
    5650          167 :   const char *mname = GET_MODE_NAME (mode);
    5651          167 :   unsigned mname_len = strlen (mname);
    5652          167 :   int len = 12 + mname_len;
    5653          167 :   if (DECIMAL_FLOAT_MODE_P (mode))
    5654           57 :     len += 4;
    5655          167 :   char *libfunc_name = XALLOCAVEC (char, len);
    5656          167 :   char *p = libfunc_name;
    5657          167 :   const char *q;
    5658          167 :   if (DECIMAL_FLOAT_MODE_P (mode))
    5659              :     {
    5660              : #if ENABLE_DECIMAL_BID_FORMAT
    5661           57 :       memcpy (p, "__bid_fix", 9);
    5662              : #else
    5663              :       memcpy (p, "__dpd_fix", 9);
    5664              : #endif
    5665           57 :       p += 9;
    5666              :     }
    5667              :   else
    5668              :     {
    5669          110 :       memcpy (p, "__fix", 5);
    5670          110 :       p += 5;
    5671              :     }
    5672          501 :   for (q = mname; *q; q++)
    5673          334 :     *p++ = TOLOWER (*q);
    5674          167 :   memcpy (p, "bitint", 7);
    5675          167 :   rtx fun = init_one_libfunc (libfunc_name);
    5676          167 :   emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
    5677              :                      SImode, arg2, mode);
    5678          167 : }
    5679              : 
    5680              : void
    5681          138 : expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
    5682              : {
    5683          138 :   tree lhs = gimple_call_lhs (stmt);
    5684          138 :   if (!lhs)
    5685              :     return;
    5686          138 :   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
    5687          138 :   rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
    5688          138 :   rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
    5689          138 :   const char *mname = GET_MODE_NAME (mode);
    5690          138 :   unsigned mname_len = strlen (mname);
    5691          138 :   int len = 14 + mname_len;
    5692          138 :   if (DECIMAL_FLOAT_MODE_P (mode))
    5693           17 :     len += 4;
    5694          138 :   char *libfunc_name = XALLOCAVEC (char, len);
    5695          138 :   char *p = libfunc_name;
    5696          138 :   const char *q;
    5697          138 :   if (DECIMAL_FLOAT_MODE_P (mode))
    5698              :     {
    5699              : #if ENABLE_DECIMAL_BID_FORMAT
    5700           17 :       memcpy (p, "__bid_floatbitint", 17);
    5701              : #else
    5702              :       memcpy (p, "__dpd_floatbitint", 17);
    5703              : #endif
    5704           17 :       p += 17;
    5705              :     }
    5706              :   else
    5707              :     {
    5708          121 :       memcpy (p, "__floatbitint", 13);
    5709          121 :       p += 13;
    5710              :     }
    5711          414 :   for (q = mname; *q; q++)
    5712          276 :     *p++ = TOLOWER (*q);
    5713          138 :   *p = '\0';
    5714          138 :   rtx fun = init_one_libfunc (libfunc_name);
    5715          138 :   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5716          138 :   rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
    5717              :                                      arg0, ptr_mode, arg1, SImode);
    5718          138 :   if (val != target)
    5719            0 :     emit_move_insn (target, val);
    5720              : }
    5721              : 
    5722              : static bool
    5723         7258 : expand_bitquery (internal_fn fn, gcall *stmt)
    5724              : {
    5725         7258 :   tree lhs = gimple_call_lhs (stmt);
    5726         7258 :   if (lhs == NULL_TREE)
    5727              :     return false;
    5728         7252 :   tree arg = gimple_call_arg (stmt, 0);
    5729         7252 :   if (TREE_CODE (arg) == INTEGER_CST)
    5730              :     {
    5731            0 :       tree ret = fold_const_call (as_combined_fn (fn), TREE_TYPE (arg), arg);
    5732            0 :       gcc_checking_assert (ret && TREE_CODE (ret) == INTEGER_CST);
    5733            0 :       expand_assignment (lhs, ret, false);
    5734            0 :       return false;
    5735              :     }
    5736              :   return true;
    5737              : }
    5738              : 
    5739              : void
    5740            1 : expand_CLRSB (internal_fn fn, gcall *stmt)
    5741              : {
    5742            1 :   if (expand_bitquery (fn, stmt))
    5743            0 :     expand_unary_optab_fn (fn, stmt, clrsb_optab);
    5744            1 : }
    5745              : 
    5746              : void
    5747         5889 : expand_CLZ (internal_fn fn, gcall *stmt)
    5748              : {
    5749         5889 :   if (expand_bitquery (fn, stmt))
    5750         5888 :     expand_unary_optab_fn (fn, stmt, clz_optab);
    5751         5889 : }
    5752              : 
    5753              : void
    5754          854 : expand_CTZ (internal_fn fn, gcall *stmt)
    5755              : {
    5756          854 :   if (expand_bitquery (fn, stmt))
    5757          853 :     expand_unary_optab_fn (fn, stmt, ctz_optab);
    5758          854 : }
    5759              : 
    5760              : void
    5761          132 : expand_FFS (internal_fn fn, gcall *stmt)
    5762              : {
    5763          132 :   if (expand_bitquery (fn, stmt))
    5764          131 :     expand_unary_optab_fn (fn, stmt, ffs_optab);
    5765          132 : }
    5766              : 
    5767              : void
    5768          165 : expand_PARITY (internal_fn fn, gcall *stmt)
    5769              : {
    5770          165 :   if (expand_bitquery (fn, stmt))
    5771          164 :     expand_unary_optab_fn (fn, stmt, parity_optab);
    5772          165 : }
    5773              : 
    5774              : void
    5775          217 : expand_POPCOUNT (internal_fn fn, gcall *stmt)
    5776              : {
    5777          217 :   if (!expand_bitquery (fn, stmt))
    5778              :     return;
    5779          216 :   if (gimple_call_num_args (stmt) == 1)
    5780              :     {
    5781          208 :       expand_unary_optab_fn (fn, stmt, popcount_optab);
    5782          208 :       return;
    5783              :     }
    5784              :   /* If .POPCOUNT call has 2 arguments, match_single_bit_test marked it
    5785              :      because the result is only used in an equality comparison against 1.
    5786              :      Use rtx costs in that case to determine if .POPCOUNT (arg) == 1
    5787              :      or (arg ^ (arg - 1)) > arg - 1 is cheaper.
    5788              :      If .POPCOUNT second argument is 0, we additionally know that arg
    5789              :      is non-zero, so use arg & (arg - 1) == 0 instead.
    5790              :      If .POPCOUNT second argument is -1, the comparison was either `<= 1`
    5791              :      or `> 1`.  */
    5792            8 :   bool speed_p = optimize_insn_for_speed_p ();
    5793            8 :   tree lhs = gimple_call_lhs (stmt);
    5794            8 :   tree arg = gimple_call_arg (stmt, 0);
    5795            8 :   bool nonzero_arg = integer_zerop (gimple_call_arg (stmt, 1));
    5796            8 :   bool was_le = integer_minus_onep (gimple_call_arg (stmt, 1));
    5797            8 :   if (was_le)
    5798            0 :     nonzero_arg = true;
    5799            8 :   tree type = TREE_TYPE (arg);
    5800            8 :   machine_mode mode = TYPE_MODE (type);
    5801            8 :   machine_mode lhsmode = TYPE_MODE (TREE_TYPE (lhs));
    5802            8 :   do_pending_stack_adjust ();
    5803            8 :   start_sequence ();
    5804            8 :   expand_unary_optab_fn (fn, stmt, popcount_optab);
    5805            8 :   rtx_insn *popcount_insns = end_sequence ();
    5806            8 :   start_sequence ();
    5807            8 :   rtx plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5808            8 :   rtx pcmp = emit_store_flag (NULL_RTX, EQ, plhs, const1_rtx, lhsmode, 0, 0);
    5809            8 :   if (pcmp == NULL_RTX)
    5810              :     {
    5811            0 :     fail:
    5812            0 :       end_sequence ();
    5813            0 :       emit_insn (popcount_insns);
    5814            0 :       return;
    5815              :     }
    5816            8 :   rtx_insn *popcount_cmp_insns = end_sequence ();
    5817            8 :   start_sequence ();
    5818            8 :   rtx op0 = expand_normal (arg);
    5819            8 :   rtx argm1 = expand_simple_binop (mode, PLUS, op0, constm1_rtx, NULL_RTX,
    5820              :                                    1, OPTAB_WIDEN);
    5821            8 :   if (argm1 == NULL_RTX)
    5822            0 :     goto fail;
    5823           12 :   rtx argxorargm1 = expand_simple_binop (mode, nonzero_arg ? AND : XOR, op0,
    5824              :                                          argm1, NULL_RTX, 1, OPTAB_WIDEN);
    5825            8 :   if (argxorargm1 == NULL_RTX)
    5826            0 :     goto fail;
    5827            8 :   rtx cmp;
    5828            8 :   if (nonzero_arg)
    5829            4 :     cmp = emit_store_flag (NULL_RTX, EQ, argxorargm1, const0_rtx, mode, 1, 1);
    5830              :   else
    5831            4 :     cmp = emit_store_flag (NULL_RTX, GTU, argxorargm1, argm1, mode, 1, 1);
    5832            8 :   if (cmp == NULL_RTX)
    5833            0 :     goto fail;
    5834            8 :   rtx_insn *cmp_insns = end_sequence ();
    5835            8 :   unsigned popcount_cost = (seq_cost (popcount_insns, speed_p)
    5836            8 :                             + seq_cost (popcount_cmp_insns, speed_p));
    5837            8 :   unsigned cmp_cost = seq_cost (cmp_insns, speed_p);
    5838              : 
    5839            8 :   if (dump_file && (dump_flags & TDF_DETAILS))
    5840            0 :     fprintf(dump_file, "popcount == 1: popcount cost: %u; cmp cost: %u\n",
    5841              :             popcount_cost, cmp_cost);
    5842              : 
    5843            8 :   if (popcount_cost <= cmp_cost)
    5844            8 :     emit_insn (popcount_insns);
    5845              :   else
    5846              :     {
    5847            0 :       start_sequence ();
    5848            0 :       emit_insn (cmp_insns);
    5849            0 :       plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
    5850            0 :       if (GET_MODE (cmp) != GET_MODE (plhs))
    5851            0 :         cmp = convert_to_mode (GET_MODE (plhs), cmp, 1);
    5852              :       /* For `<= 1`, we need to produce `2 - cmp` or `cmp ? 1 : 2` as that
    5853              :          then gets compared against 1 and we need the false case to be 2.  */
    5854            0 :       if (was_le)
    5855              :         {
    5856            0 :           cmp = expand_simple_binop (GET_MODE (cmp), MINUS, const2_rtx,
    5857              :                                      cmp, NULL_RTX, 1, OPTAB_WIDEN);
    5858            0 :           if (!cmp)
    5859            0 :             goto fail;
    5860              :         }
    5861            0 :       emit_move_insn (plhs, cmp);
    5862            0 :       rtx_insn *all_insns = end_sequence ();
    5863            0 :       emit_insn (all_insns);
    5864              :     }
    5865              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.