LCOV - code coverage report
Current view: top level - gcc - optabs-query.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.2 % 336 293
Test Date: 2026-07-11 15:47:05 Functions: 96.6 % 29 28
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* IR-agnostic target query functions relating to optabs
       2              :    Copyright (C) 1987-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              : 
      21              : #include "config.h"
      22              : #include "system.h"
      23              : #include "coretypes.h"
      24              : #include "target.h"
      25              : #include "insn-codes.h"
      26              : #include "optabs-query.h"
      27              : #include "optabs-libfuncs.h"
      28              : #include "insn-config.h"
      29              : #include "rtl.h"
      30              : #include "recog.h"
      31              : #include "vec-perm-indices.h"
      32              : #include "internal-fn.h"
      33              : #include "memmodel.h"
      34              : #include "optabs.h"
      35              : 
      36              : struct target_optabs default_target_optabs;
      37              : struct target_optabs *this_fn_optabs = &default_target_optabs;
      38              : #if SWITCHABLE_TARGET
      39              : struct target_optabs *this_target_optabs = &default_target_optabs;
      40              : #endif
      41              : 
      42              : /* Return the insn used to perform conversion OP from mode FROM_MODE
      43              :    to mode TO_MODE; return CODE_FOR_nothing if the target does not have
      44              :    such an insn, or if it is unsuitable for optimization type OPT_TYPE.  */
      45              : 
      46              : insn_code
      47       118837 : convert_optab_handler (convert_optab optab, machine_mode to_mode,
      48              :                        machine_mode from_mode, optimization_type opt_type)
      49              : {
      50       118837 :   insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
      51       118837 :   if (icode == CODE_FOR_nothing
      52       118837 :       || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
      53       118203 :     return CODE_FOR_nothing;
      54              :   return icode;
      55              : }
      56              : 
      57              : /* Return the insn used to implement mode MODE of OP; return
      58              :    CODE_FOR_nothing if the target does not have such an insn,
      59              :    or if it is unsuitable for optimization type OPT_TYPE.  */
      60              : 
      61              : insn_code
      62      4183556 : direct_optab_handler (convert_optab optab, machine_mode mode,
      63              :                       optimization_type opt_type)
      64              : {
      65      4183556 :   insn_code icode = direct_optab_handler (optab, mode);
      66      4183556 :   if (icode == CODE_FOR_nothing
      67      4183556 :       || !targetm.optab_supported_p (optab, mode, mode, opt_type))
      68      3803633 :     return CODE_FOR_nothing;
      69              :   return icode;
      70              : }
      71              : 
      72              : /* Enumerates the possible types of structure operand to an
      73              :    extraction_insn.  */
      74              : enum extraction_type { ET_unaligned_mem, ET_reg };
      75              : 
      76              : /* Check whether insv, extv or extzv pattern ICODE can be used for an
      77              :    insertion or extraction of type TYPE on a structure of mode MODE.
      78              :    Return true if so and fill in *INSN accordingly.  STRUCT_OP is the
      79              :    operand number of the structure (the first sign_extract or zero_extract
      80              :    operand) and FIELD_OP is the operand number of the field (the other
      81              :    side of the set from the sign_extract or zero_extract).  */
      82              : 
      83              : static bool
      84            0 : get_traditional_extraction_insn (extraction_insn *insn,
      85              :                                  enum extraction_type type,
      86              :                                  machine_mode mode,
      87              :                                  enum insn_code icode,
      88              :                                  int struct_op, int field_op)
      89              : {
      90            0 :   const struct insn_data_d *data = &insn_data[icode];
      91              : 
      92            0 :   machine_mode struct_mode = data->operand[struct_op].mode;
      93            0 :   if (struct_mode == VOIDmode)
      94            0 :     struct_mode = word_mode;
      95            0 :   if (mode != struct_mode)
      96              :     return false;
      97              : 
      98            0 :   machine_mode field_mode = data->operand[field_op].mode;
      99            0 :   if (field_mode == VOIDmode)
     100            0 :     field_mode = word_mode;
     101              : 
     102            0 :   machine_mode pos_mode = data->operand[struct_op + 2].mode;
     103            0 :   if (pos_mode == VOIDmode)
     104            0 :     pos_mode = word_mode;
     105              : 
     106            0 :   insn->icode = icode;
     107            0 :   insn->field_mode = as_a <scalar_int_mode> (field_mode);
     108            0 :   if (type == ET_unaligned_mem)
     109            0 :     insn->struct_mode = byte_mode;
     110            0 :   else if (struct_mode == BLKmode)
     111            0 :     insn->struct_mode = opt_scalar_int_mode ();
     112              :   else
     113            0 :     insn->struct_mode = as_a <scalar_int_mode> (struct_mode);
     114            0 :   insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
     115            0 :   return true;
     116              : }
     117              : 
     118              : /* Return true if an optab exists to perform an insertion or extraction
     119              :    of type TYPE in mode MODE.  Describe the instruction in *INSN if so.
     120              : 
     121              :    REG_OPTAB is the optab to use for register structures and
     122              :    MISALIGN_OPTAB is the optab to use for misaligned memory structures.
     123              :    POS_OP is the operand number of the bit position.  */
     124              : 
     125              : static bool
     126      3534191 : get_optab_extraction_insn (class extraction_insn *insn,
     127              :                            enum extraction_type type,
     128              :                            machine_mode mode, direct_optab reg_optab,
     129              :                            direct_optab misalign_optab, int pos_op)
     130              : {
     131      3534191 :   direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
     132      3534191 :   enum insn_code icode = direct_optab_handler (optab, mode);
     133      3534191 :   if (icode == CODE_FOR_nothing)
     134              :     return false;
     135              : 
     136      1623456 :   const struct insn_data_d *data = &insn_data[icode];
     137              : 
     138      1623456 :   machine_mode pos_mode = data->operand[pos_op].mode;
     139      1623456 :   if (pos_mode == VOIDmode)
     140            0 :     pos_mode = word_mode;
     141              : 
     142      1623456 :   insn->icode = icode;
     143      1623456 :   insn->field_mode = as_a <scalar_int_mode> (mode);
     144      1623456 :   if (type == ET_unaligned_mem)
     145            0 :     insn->struct_mode = opt_scalar_int_mode ();
     146              :   else
     147      1623456 :     insn->struct_mode = insn->field_mode;
     148      1623456 :   insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
     149      1623456 :   return true;
     150              : }
     151              : 
     152              : /* Return true if an instruction exists to perform an insertion or
     153              :    extraction (PATTERN says which) of type TYPE in mode MODE.
     154              :    Describe the instruction in *INSN if so.  */
     155              : 
     156              : static bool
     157      3534191 : get_extraction_insn (extraction_insn *insn,
     158              :                      enum extraction_pattern pattern,
     159              :                      enum extraction_type type,
     160              :                      machine_mode mode)
     161              : {
     162      3534191 :   switch (pattern)
     163              :     {
     164       540757 :     case EP_insv:
     165       540757 :       if (targetm.have_insv ()
     166       540757 :           && get_traditional_extraction_insn (insn, type, mode,
     167              :                                               targetm.code_for_insv, 0, 3))
     168              :         return true;
     169       540757 :       return get_optab_extraction_insn (insn, type, mode, insv_optab,
     170       540757 :                                         insvmisalign_optab, 2);
     171              : 
     172       769004 :     case EP_extv:
     173       769004 :       if (targetm.have_extv ()
     174       769004 :           && get_traditional_extraction_insn (insn, type, mode,
     175              :                                               targetm.code_for_extv, 1, 0))
     176              :         return true;
     177       769004 :       return get_optab_extraction_insn (insn, type, mode, extv_optab,
     178       769004 :                                         extvmisalign_optab, 3);
     179              : 
     180      2224430 :     case EP_extzv:
     181      2224430 :       if (targetm.have_extzv ()
     182      2224430 :           && get_traditional_extraction_insn (insn, type, mode,
     183              :                                               targetm.code_for_extzv, 1, 0))
     184              :         return true;
     185      2224430 :       return get_optab_extraction_insn (insn, type, mode, extzv_optab,
     186      2224430 :                                         extzvmisalign_optab, 3);
     187              : 
     188            0 :     default:
     189            0 :       gcc_unreachable ();
     190              :     }
     191              : }
     192              : 
     193              : /* Return true if an instruction exists to access a field of mode
     194              :    FIELDMODE in a structure that has STRUCT_BITS significant bits.
     195              :    Describe the "best" such instruction in *INSN if so.  PATTERN and
     196              :    TYPE describe the type of insertion or extraction we want to perform.
     197              : 
     198              :    For an insertion, the number of significant structure bits includes
     199              :    all bits of the target.  For an extraction, it need only include the
     200              :    most significant bit of the field.  Larger widths are acceptable
     201              :    in both cases.  */
     202              : 
     203              : static bool
     204      1947529 : get_best_extraction_insn (extraction_insn *insn,
     205              :                           enum extraction_pattern pattern,
     206              :                           enum extraction_type type,
     207              :                           unsigned HOST_WIDE_INT struct_bits,
     208              :                           machine_mode field_mode)
     209              : {
     210      1947529 :   opt_scalar_int_mode mode_iter;
     211              : 
     212      3858264 :   FOR_EACH_MODE_FROM (mode_iter, smallest_int_mode_for_size (struct_bits))
     213              :     {
     214      3534191 :       scalar_int_mode mode = mode_iter.require ();
     215      3534191 :       if (get_extraction_insn (insn, pattern, type, mode))
     216              :         {
     217      1623456 :           FOR_EACH_MODE_FROM (mode_iter, mode)
     218              :             {
     219      1623456 :               mode = mode_iter.require ();
     220      3246912 :               if (maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (field_mode))
     221      1623456 :                   || TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
     222              :                                                     field_mode))
     223              :                 break;
     224            0 :               get_extraction_insn (insn, pattern, type, mode);
     225              :             }
     226      1623456 :           return true;
     227              :         }
     228              :     }
     229              :   return false;
     230              : }
     231              : 
     232              : /* Return true if an instruction exists to access a field of mode
     233              :    FIELDMODE in a register structure that has STRUCT_BITS significant bits.
     234              :    Describe the "best" such instruction in *INSN if so.  PATTERN describes
     235              :    the type of insertion or extraction we want to perform.
     236              : 
     237              :    For an insertion, the number of significant structure bits includes
     238              :    all bits of the target.  For an extraction, it need only include the
     239              :    most significant bit of the field.  Larger widths are acceptable
     240              :    in both cases.  */
     241              : 
     242              : bool
     243      1743221 : get_best_reg_extraction_insn (extraction_insn *insn,
     244              :                               enum extraction_pattern pattern,
     245              :                               unsigned HOST_WIDE_INT struct_bits,
     246              :                               machine_mode field_mode)
     247              : {
     248      1743221 :   return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
     249      1743221 :                                    field_mode);
     250              : }
     251              : 
     252              : /* Return true if an instruction exists to access a field of BITSIZE
     253              :    bits starting BITNUM bits into a memory structure.  Describe the
     254              :    "best" such instruction in *INSN if so.  PATTERN describes the type
     255              :    of insertion or extraction we want to perform and FIELDMODE is the
     256              :    natural mode of the extracted field.
     257              : 
     258              :    The instructions considered here only access bytes that overlap
     259              :    the bitfield; they do not touch any surrounding bytes.  */
     260              : 
     261              : bool
     262       204308 : get_best_mem_extraction_insn (extraction_insn *insn,
     263              :                               enum extraction_pattern pattern,
     264              :                               HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
     265              :                               machine_mode field_mode)
     266              : {
     267       204308 :   unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
     268       204308 :                                         + bitsize
     269       204308 :                                         + BITS_PER_UNIT - 1);
     270       204308 :   struct_bits -= struct_bits % BITS_PER_UNIT;
     271       204308 :   return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
     272       204308 :                                    struct_bits, field_mode);
     273              : }
     274              : 
     275              : /* Return the insn code used to extend FROM_MODE to TO_MODE.
     276              :    UNSIGNEDP specifies zero-extension instead of sign-extension.  If
     277              :    no such operation exists, CODE_FOR_nothing will be returned.  */
     278              : 
     279              : enum insn_code
     280      5497962 : can_extend_p (machine_mode to_mode, machine_mode from_mode,
     281              :               int unsignedp)
     282              : {
     283      5497962 :   if (unsignedp < 0 && targetm.have_ptr_extend ())
     284            0 :     return targetm.code_for_ptr_extend;
     285              : 
     286      5497962 :   convert_optab tab = unsignedp ? zext_optab : sext_optab;
     287      5497962 :   return convert_optab_handler (tab, to_mode, from_mode);
     288              : }
     289              : 
     290              : /* Return the insn code to convert fixed-point mode FIXMODE to floating-point
     291              :    mode FLTMODE, or CODE_FOR_nothing if no such instruction exists.
     292              :    UNSIGNEDP specifies whether FIXMODE is unsigned.  */
     293              : 
     294              : enum insn_code
     295       377113 : can_float_p (machine_mode fltmode, machine_mode fixmode,
     296              :              int unsignedp)
     297              : {
     298       377113 :   convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
     299       377113 :   return convert_optab_handler (tab, fltmode, fixmode);
     300              : }
     301              : 
     302              : /* Return the insn code to convert floating-point mode FLTMODE to fixed-point
     303              :    mode FIXMODE, or CODE_FOR_nothing if no such instruction exists.
     304              :    UNSIGNEDP specifies whether FIXMODE is unsigned.
     305              : 
     306              :    On a successful return, set *TRUNCP_PTR to true if it is necessary to
     307              :    output an explicit FTRUNC before the instruction.  */
     308              : 
     309              : enum insn_code
     310       254238 : can_fix_p (machine_mode fixmode, machine_mode fltmode,
     311              :            int unsignedp, bool *truncp_ptr)
     312              : {
     313       254238 :   convert_optab tab;
     314       254238 :   enum insn_code icode;
     315              : 
     316       254238 :   tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
     317       254238 :   icode = convert_optab_handler (tab, fixmode, fltmode);
     318       254238 :   if (icode != CODE_FOR_nothing)
     319              :     {
     320        51334 :       *truncp_ptr = false;
     321        51334 :       return icode;
     322              :     }
     323              : 
     324              :   /* FIXME: This requires a port to define both FIX and FTRUNC pattern
     325              :      for this to work.  We need to rework the fix* and ftrunc* patterns
     326              :      and documentation.  */
     327       202904 :   tab = unsignedp ? ufix_optab : sfix_optab;
     328       202904 :   icode = convert_optab_handler (tab, fixmode, fltmode);
     329       202904 :   if (icode != CODE_FOR_nothing
     330       202904 :       && optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
     331              :     {
     332            0 :       *truncp_ptr = true;
     333            0 :       return icode;
     334              :     }
     335              : 
     336              :   return CODE_FOR_nothing;
     337              : }
     338              : 
     339              : /* Return nonzero if a conditional move of mode MODE is supported.
     340              : 
     341              :    This function is for combine so it can tell whether an insn that looks
     342              :    like a conditional move is actually supported by the hardware.  If we
     343              :    guess wrong we lose a bit on optimization, but that's it.  */
     344              : /* ??? sparc64 supports conditionally moving integers values based on fp
     345              :    comparisons, and vice versa.  How do we handle them?  */
     346              : 
     347              : bool
     348      1191043 : can_conditionally_move_p (machine_mode mode)
     349              : {
     350      1191043 :   return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
     351              : }
     352              : 
     353              : /* If a target doesn't implement a permute on a vector with multibyte
     354              :    elements, we can try to do the same permute on byte elements.
     355              :    If this makes sense for vector mode MODE then return the appropriate
     356              :    byte vector mode.  */
     357              : 
     358              : opt_machine_mode
     359       780236 : qimode_for_vec_perm (machine_mode mode)
     360              : {
     361       780236 :   if (GET_MODE_INNER (mode) != QImode
     362      1512936 :       && multiple_p (GET_MODE_PRECISION (GET_MODE_INNER (mode)),
     363       732700 :                      GET_MODE_PRECISION (QImode)))
     364      1465400 :     return related_vector_mode (mode, QImode, GET_MODE_SIZE (mode));
     365        47536 :   return opt_machine_mode ();
     366              : }
     367              : 
     368              : /* Return true if selector SEL can be represented in the integer
     369              :    equivalent of vector mode MODE.  */
     370              : 
     371              : bool
     372      1529618 : selector_fits_mode_p (machine_mode mode, const vec_perm_indices &sel)
     373              : {
     374      1529618 :   unsigned HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE_INNER (mode));
     375      1529618 :   return (mask == HOST_WIDE_INT_M1U
     376      1529618 :           || sel.all_in_range_p (0, mask + 1));
     377              : }
     378              : 
     379              : /* Return true if VEC_PERM_EXPRs with variable selector operands can be
     380              :    expanded using SIMD extensions of the CPU.  MODE is the mode of the
     381              :    vectors being permuted.  */
     382              : 
     383              : bool
     384          880 : can_vec_perm_var_p (machine_mode mode)
     385              : {
     386              :   /* If the target doesn't implement a vector mode for the vector type,
     387              :      then no operations are supported.  */
     388          880 :   if (!VECTOR_MODE_P (mode))
     389              :     return false;
     390              : 
     391          629 :   if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
     392              :     return true;
     393              : 
     394              :   /* We allow fallback to a QI vector mode, and adjust the mask.  */
     395          610 :   machine_mode qimode;
     396          610 :   if (!qimode_for_vec_perm (mode).exists (&qimode)
     397          988 :       || maybe_gt (GET_MODE_NUNITS (qimode), GET_MODE_MASK (QImode) + 1))
     398          116 :     return false;
     399              : 
     400          494 :   if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
     401              :     return false;
     402              : 
     403              :   /* In order to support the lowering of variable permutations,
     404              :      we need to support shifts and adds.  */
     405            0 :   if (GET_MODE_UNIT_SIZE (mode) > 2
     406            0 :       && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
     407            0 :       && optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
     408              :     return false;
     409            0 :   if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
     410              :     return false;
     411              : 
     412              :   return true;
     413              : }
     414              : 
     415              : /* Return true if the target directly supports VEC_PERM_EXPRs on vectors
     416              :    of mode OP_MODE and result vector of mode MODE using the selector SEL.
     417              :    ALLOW_VARIABLE_P is true if it is acceptable to force the selector into a
     418              :    register and use a variable permute (if the target supports that).  */
     419              : 
     420              : bool
     421       909256 : can_vec_perm_const_p (machine_mode mode, machine_mode op_mode,
     422              :                       const vec_perm_indices &sel, bool allow_variable_p)
     423              : {
     424              :   /* If the target doesn't implement a vector mode for the vector type,
     425              :      then no operations are supported.  */
     426       909256 :   if (!VECTOR_MODE_P (mode))
     427              :     return false;
     428              : 
     429              :   /* It's probably cheaper to test for the variable case first.  */
     430       907022 :   if (op_mode == mode && allow_variable_p && selector_fits_mode_p (mode, sel))
     431              :     {
     432       866217 :       if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
     433       909256 :         return true;
     434              : 
     435              :       /* Unlike can_vec_perm_var_p, we don't need to test for optabs
     436              :          related computing the QImode selector, since that happens at
     437              :          compile time.  */
     438       703674 :       machine_mode qimode;
     439       703674 :       if (qimode_for_vec_perm (mode).exists (&qimode))
     440              :         {
     441       663401 :           vec_perm_indices qimode_indices;
     442      1326802 :           qimode_indices.new_expanded_vector (sel, GET_MODE_UNIT_SIZE (mode));
     443       663401 :           if (selector_fits_mode_p (qimode, qimode_indices)
     444       663401 :               && (direct_optab_handler (vec_perm_optab, qimode)
     445              :                   != CODE_FOR_nothing))
     446            4 :             return true;
     447       663401 :         }
     448              :     }
     449              : 
     450       744475 :   if (targetm.vectorize.vec_perm_const != NULL)
     451              :     {
     452       744475 :       if (targetm.vectorize.vec_perm_const (mode, op_mode, NULL_RTX, NULL_RTX,
     453              :                                             NULL_RTX, sel))
     454              :         return true;
     455              : 
     456              :       /* ??? For completeness, we ought to check the QImode version of
     457              :          vec_perm_const_optab.  But all users of this implicit lowering
     458              :          feature implement the variable vec_perm_optab, and the ia64
     459              :          port specifically doesn't want us to lower V2SF operations
     460              :          into integer operations.  */
     461              :     }
     462              : 
     463        24810 :   unsigned elements;
     464        24810 :   if (mode == op_mode
     465        47761 :       && GET_MODE_NUNITS (mode).is_constant (&elements))
     466              :     {
     467        22951 :       if (sel.input_bitwise_zero_p (0)
     468        22951 :           && can_implement_p (vec_shl_optab, mode))
     469              :         {
     470              :           unsigned int first = 0, i;
     471          354 :           for (i = 0; i < elements; ++i)
     472          286 :             if (known_eq (poly_uint64 (sel[i]), elements))
     473              :               {
     474           66 :                 if (i == 0 || first)
     475              :                   break;
     476              :                 first = i;
     477              :               }
     478          440 :             else if (first
     479          440 :                      ? maybe_ne (poly_uint64 (sel[i]),
     480           75 :                                  elements + i - first)
     481          220 :                      : maybe_ge (poly_uint64 (sel[i]), elements))
     482              :               break;
     483           69 :           if (first && i == elements)
     484              :             return true;
     485              :         }
     486        22885 :       if (sel.input_bitwise_zero_p (1)
     487           46 :           && maybe_ne (sel[0], 0)
     488        22885 :           && known_lt (sel[0], elements)
     489        22921 :           && can_implement_p (vec_shr_optab, mode))
     490              :         {
     491           36 :           if (sel.series_p (0, 1, sel[0], 1))
     492              :             return true;
     493              :           unsigned i;
     494           33 :           for (i = 1; i < elements; ++i)
     495              :             {
     496           33 :               poly_uint64 actual = sel[i];
     497           33 :               poly_uint64 expected = i + sel[0];
     498              :               /* Indices into the second vector are all equivalent.  */
     499           66 :               if (maybe_lt (actual, elements)
     500           33 :                   ? maybe_ne (actual, expected)
     501            9 :                   : maybe_lt (expected, elements))
     502              :                 break;
     503              :             }
     504            9 :           if (i == elements)
     505              :             return true;
     506              :         }
     507              :     }
     508              : 
     509              :   return false;
     510              : }
     511              : 
     512              : /* Find a widening optab even if it doesn't widen as much as we want.
     513              :    E.g. if from_mode is HImode, and to_mode is DImode, and there is no
     514              :    direct HI->SI insn, then return SI->DI, if that exists.  */
     515              : 
     516              : enum insn_code
     517       311239 : find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
     518              :                                       machine_mode from_mode,
     519              :                                       machine_mode *found_mode)
     520              : {
     521       311239 :   machine_mode limit_mode = to_mode;
     522       311239 :   if (is_a <scalar_int_mode> (from_mode))
     523              :     {
     524       310556 :       gcc_checking_assert (is_a <scalar_int_mode> (to_mode)
     525              :                            && known_lt (GET_MODE_PRECISION (from_mode),
     526              :                                         GET_MODE_PRECISION (to_mode)));
     527              :       /* The modes after FROM_MODE are all MODE_INT, so the only
     528              :          MODE_PARTIAL_INT mode we consider is FROM_MODE itself.
     529              :          If LIMIT_MODE is MODE_PARTIAL_INT, stop at the containing
     530              :          MODE_INT.  */
     531       310556 :       if (GET_MODE_CLASS (limit_mode) == MODE_PARTIAL_INT)
     532            0 :         limit_mode = GET_MODE_WIDER_MODE (limit_mode).require ();
     533              :     }
     534          683 :   else if (is_a <scalar_int_mode> (to_mode))
     535              :     {
     536            0 :       gcc_checking_assert (VECTOR_MODE_P (from_mode)
     537              :                            && GET_MODE_INNER (from_mode) < to_mode);
     538            0 :       limit_mode = GET_MODE_NEXT_MODE (from_mode).require ();
     539              :     }
     540              :   else
     541          683 :     gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
     542              :                          && from_mode < to_mode);
     543       584171 :   FOR_EACH_MODE (from_mode, from_mode, limit_mode)
     544              :     {
     545       334241 :       enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
     546              : 
     547       334241 :       if (handler != CODE_FOR_nothing)
     548              :         {
     549        61309 :           if (found_mode)
     550        10097 :             *found_mode = from_mode;
     551        61309 :           return handler;
     552              :         }
     553              :     }
     554              : 
     555              :   return CODE_FOR_nothing;
     556              : }
     557              : 
     558              : /* Return non-zero if a highpart multiply is supported or can be synthesized.
     559              :    For the benefit of expand_mult_highpart, the return value is 1 for direct,
     560              :    2 for integral widening, 3 for even/odd widening, 4 for hi/lo widening.  */
     561              : 
     562              : int
     563        80328 : can_mult_highpart_p (machine_mode mode, bool uns_p)
     564              : {
     565        80328 :   optab op;
     566        80328 :   scalar_int_mode int_mode, wider_mode;
     567              : 
     568        80328 :   op = uns_p ? umul_highpart_optab : smul_highpart_optab;
     569        80328 :   if (optab_handler (op, mode) != CODE_FOR_nothing)
     570              :     return 1;
     571              : 
     572              :   /* If the mode is integral, synth from widening or larger operations.  */
     573        76771 :   if (is_a <scalar_int_mode> (mode, &int_mode)
     574         4783 :       && GET_MODE_WIDER_MODE (int_mode).exists (&wider_mode))
     575              :     {
     576         4783 :       op = uns_p ? umul_widen_optab : smul_widen_optab;
     577         4783 :       if (convert_optab_handler (op, wider_mode, mode) != CODE_FOR_nothing)
     578              :         return 2;
     579              : 
     580              :       /* The test on the size comes from expmed_mult_highpart_optab.  */
     581         4783 :       if (optab_handler (smul_optab, wider_mode) != CODE_FOR_nothing
     582         4783 :           && GET_MODE_BITSIZE (int_mode) - 1 < BITS_PER_WORD)
     583              :         return 2;
     584              :     }
     585              : 
     586              :   /* If the mode is an integral vector, synth from widening operations.  */
     587        76771 :   if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
     588              :     return 0;
     589              : 
     590       143976 :   poly_int64 nunits = GET_MODE_NUNITS (mode);
     591              : 
     592        71988 :   op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
     593        71988 :   if (optab_handler (op, mode) != CODE_FOR_nothing)
     594              :     {
     595        20830 :       op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
     596        20830 :       if (optab_handler (op, mode) != CODE_FOR_nothing)
     597              :         {
     598              :           /* The encoding has 2 interleaved stepped patterns.  */
     599        20830 :           vec_perm_builder sel (nunits, 2, 3);
     600       145810 :           for (unsigned int i = 0; i < 6; ++i)
     601       249960 :             sel.quick_push (!BYTES_BIG_ENDIAN
     602       124980 :                             + (i & ~1)
     603       187470 :                             + ((i & 1) ? nunits : 0));
     604        20830 :           vec_perm_indices indices (sel, 2, nunits);
     605        20830 :           if (can_vec_perm_const_p (mode, mode, indices))
     606        20830 :             return 3;
     607        20830 :         }
     608              :     }
     609              : 
     610        51158 :   op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
     611        51158 :   if (optab_handler (op, mode) != CODE_FOR_nothing)
     612              :     {
     613          283 :       op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
     614          283 :       if (optab_handler (op, mode) != CODE_FOR_nothing)
     615              :         {
     616              :           /* The encoding has a single stepped pattern.  */
     617          283 :           vec_perm_builder sel (nunits, 1, 3);
     618         1132 :           for (unsigned int i = 0; i < 3; ++i)
     619          849 :             sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1));
     620          283 :           vec_perm_indices indices (sel, 2, nunits);
     621          283 :           if (can_vec_perm_const_p (mode, mode, indices))
     622          283 :             return 4;
     623          283 :         }
     624              :     }
     625              : 
     626              :   return 0;
     627              : }
     628              : 
     629              : /* Return true if there is a compare_and_swap pattern.  */
     630              : 
     631              : bool
     632       164593 : can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
     633              : {
     634       164593 :   enum insn_code icode;
     635              : 
     636              :   /* Check for __atomic_compare_and_swap.  */
     637       164593 :   icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
     638       164593 :   if (icode != CODE_FOR_nothing)
     639              :     return true;
     640              : 
     641              :   /* Check for __sync_compare_and_swap.  */
     642          137 :   icode = optab_handler (sync_compare_and_swap_optab, mode);
     643          137 :   if (icode != CODE_FOR_nothing)
     644              :     return true;
     645          137 :   if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
     646              :     return true;
     647              : 
     648              :   /* No inline compare and swap.  */
     649              :   return false;
     650              : }
     651              : 
     652              : /* Return true if an atomic exchange can be performed.  */
     653              : 
     654              : bool
     655           88 : can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
     656              : {
     657           88 :   enum insn_code icode;
     658              : 
     659              :   /* Check for __atomic_exchange.  */
     660           88 :   icode = direct_optab_handler (atomic_exchange_optab, mode);
     661           88 :   if (icode != CODE_FOR_nothing)
     662              :     return true;
     663              : 
     664              :   /* Don't check __sync_test_and_set, as on some platforms that
     665              :      has reduced functionality.  Targets that really do support
     666              :      a proper exchange should simply be updated to the __atomics.  */
     667              : 
     668            0 :   return can_compare_and_swap_p (mode, allow_libcall);
     669              : }
     670              : 
     671              : /* Return true if an atomic load can be performed without falling back to
     672              :    a compare-and-swap.  */
     673              : 
     674              : bool
     675       219627 : can_atomic_load_p (machine_mode mode)
     676              : {
     677       219627 :   enum insn_code icode;
     678              : 
     679              :   /* Does the target supports the load directly?  */
     680       219627 :   icode = direct_optab_handler (atomic_load_optab, mode);
     681       219627 :   if (icode != CODE_FOR_nothing)
     682              :     return true;
     683              : 
     684              :   /* If the size of the object is greater than word size on this target,
     685              :      then we assume that a load will not be atomic.  Also see
     686              :      expand_atomic_load.  */
     687         4046 :   return known_le (GET_MODE_PRECISION (mode), BITS_PER_WORD);
     688              : }
     689              : 
     690              : /* Determine whether "1 << x" is relatively cheap in word_mode.  */
     691              : 
     692              : bool
     693      1074619 : lshift_cheap_p (bool speed_p)
     694              : {
     695              :   /* FIXME: This should be made target dependent via this "this_target"
     696              :      mechanism, similar to e.g. can_copy_init_p in gcse.cc.  */
     697      1074619 :   static bool init[2] = { false, false };
     698      1074619 :   static bool cheap[2] = { true, true };
     699              : 
     700              :   /* If the target has no lshift in word_mode, the operation will most
     701              :      probably not be cheap.  ??? Does GCC even work for such targets?  */
     702      1074619 :   if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
     703              :     return false;
     704              : 
     705      1074619 :   if (!init[speed_p])
     706              :     {
     707        41953 :       rtx reg = gen_raw_REG (word_mode, 10000);
     708        41953 :       int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
     709              :                                word_mode, speed_p);
     710        41953 :       cheap[speed_p] = cost < COSTS_N_INSNS (3);
     711        41953 :       init[speed_p] = true;
     712              :     }
     713              : 
     714      1074619 :   return cheap[speed_p];
     715              : }
     716              : 
     717              : /* If MODE is not VOIDmode, return true if vector conversion optab OP supports
     718              :    that mode, given that the second mode is always an integer vector.
     719              :    If MODE is VOIDmode, return true if OP supports any vector mode.  */
     720              : 
     721              : static enum insn_code
     722       177786 : supported_vec_convert_optab (optab op, machine_mode mode)
     723              : {
     724       177786 :   int start = mode == VOIDmode ? 0 : mode;
     725       177786 :   int end = mode == VOIDmode ? MAX_MACHINE_MODE - 1 : mode;
     726       177786 :   enum insn_code icode = CODE_FOR_nothing;
     727       355572 :   for (int i = start; i <= end; ++i)
     728       177786 :     if (VECTOR_MODE_P ((machine_mode) i))
     729      5511366 :       for (int j = MIN_MODE_VECTOR_INT; j < MAX_MODE_VECTOR_INT; ++j)
     730              :         {
     731     10667160 :           if ((icode
     732      5333580 :                = convert_optab_handler (op, (machine_mode) i,
     733              :                                         (machine_mode) j)) != CODE_FOR_nothing)
     734              :             return icode;
     735              :         }
     736              : 
     737              :   return icode;
     738              : }
     739              : 
     740              : /* If MODE is not VOIDmode, return true if vec_gather_load is available for
     741              :    that mode.  If MODE is VOIDmode, return true if gather_load is available
     742              :    for at least one vector mode.
     743              :    In that case, and if ELSVALS is nonzero, store the supported else values
     744              :    into the vector it points to.  */
     745              : 
     746              : bool
     747       267399 : supports_vec_gather_load_p (machine_mode mode, vec<int> *elsvals)
     748              : {
     749       267399 :   enum insn_code icode = CODE_FOR_nothing;
     750       267399 :   if (!this_fn_optabs->supports_vec_gather_load[mode] || elsvals)
     751              :     {
     752              :       /* Try the masked variants first.  In case we later decide that we
     753              :          need a mask after all (thus requiring an else operand) we need
     754              :          to query it below and we cannot do that when using the
     755              :          non-masked optab.  */
     756        51314 :       icode = supported_vec_convert_optab (mask_gather_load_optab, mode);
     757        51314 :       if (icode == CODE_FOR_nothing)
     758        51314 :         icode = supported_vec_convert_optab (mask_len_gather_load_optab, mode);
     759        51314 :       if (icode == CODE_FOR_nothing)
     760        51314 :         icode = supported_vec_convert_optab (gather_load_optab, mode);
     761       102628 :       this_fn_optabs->supports_vec_gather_load[mode]
     762       102628 :         = (icode != CODE_FOR_nothing) ? 1 : -1;
     763              :     }
     764              : 
     765       267399 :   if (elsvals && icode != CODE_FOR_nothing)
     766            0 :     get_supported_else_vals
     767            0 :       (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
     768              : 
     769       267399 :   return this_fn_optabs->supports_vec_gather_load[mode] > 0;
     770              : }
     771              : 
     772              : /* If MODE is not VOIDmode, return true if vec_scatter_store is available for
     773              :    that mode.  If MODE is VOIDmode, return true if scatter_store is available
     774              :    for at least one vector mode.  */
     775              : 
     776              : bool
     777        87065 : supports_vec_scatter_store_p (machine_mode mode)
     778              : {
     779        87065 :   enum insn_code icode;
     780        87065 :   if (!this_fn_optabs->supports_vec_scatter_store[mode])
     781              :     {
     782         7948 :       icode = supported_vec_convert_optab (scatter_store_optab, mode);
     783         7948 :       if (icode == CODE_FOR_nothing)
     784         7948 :         icode = supported_vec_convert_optab (mask_scatter_store_optab, mode);
     785         7948 :       if (icode == CODE_FOR_nothing)
     786         7948 :         icode = supported_vec_convert_optab (mask_len_scatter_store_optab,
     787              :                                               mode);
     788        15896 :       this_fn_optabs->supports_vec_scatter_store[mode]
     789         7948 :         = (icode != CODE_FOR_nothing) ? 1 : -1;
     790              :     }
     791              : 
     792        87065 :   return this_fn_optabs->supports_vec_scatter_store[mode] > 0;
     793              : }
     794              : 
     795              : /* Whether we can extract part of the vector mode MODE as
     796              :    (scalar or vector) mode EXTR_MODE.  */
     797              : 
     798              : bool
     799         4279 : can_vec_extract (machine_mode mode, machine_mode extr_mode)
     800              : {
     801         4279 :   unsigned m;
     802         2616 :   if (!VECTOR_MODE_P (mode)
     803         8558 :       || !constant_multiple_p (GET_MODE_SIZE (mode),
     804         4275 :                                GET_MODE_SIZE (extr_mode), &m))
     805              :     return false;
     806              : 
     807         4275 :   if (convert_optab_handler (vec_extract_optab, mode, extr_mode)
     808              :       != CODE_FOR_nothing)
     809              :     return true;
     810              : 
     811              :   /* Besides a direct vec_extract we can also use an element extract from
     812              :      an integer vector mode with elements of the size of the extr_mode.  */
     813         1694 :   scalar_int_mode imode;
     814         1694 :   machine_mode vmode;
     815         3388 :   if (!int_mode_for_size (GET_MODE_BITSIZE (extr_mode), 0).exists (&imode)
     816         3388 :       || !related_vector_mode (mode, imode, m).exists (&vmode)
     817         1694 :       || (convert_optab_handler (vec_extract_optab, vmode, imode)
     818              :           == CODE_FOR_nothing))
     819            0 :     return false;
     820              :   /* We assume we can pun mode to vmode and imode to extr_mode.  */
     821              :   return true;
     822              : }
     823              : 
     824              : /* OP is either neg_optab or abs_optab and FMODE is the floating-point inner
     825              :    mode of MODE.  Check whether we can implement OP for mode MODE by using
     826              :    xor_optab to flip the sign bit (for neg_optab) or and_optab to clear the
     827              :    sign bit (for abs_optab).  If so, return the integral mode that should be
     828              :    used to do the operation and set *BITPOS to the index of the sign bit
     829              :    (counting from the lsb).  */
     830              : 
     831              : opt_machine_mode
     832         1268 : get_absneg_bit_mode (optab op, machine_mode mode,
     833              :                      scalar_float_mode fmode, int *bitpos)
     834              : {
     835              :   /* The format has to have a simple sign bit.  */
     836         1268 :   auto fmt = REAL_MODE_FORMAT (fmode);
     837         1268 :   if (fmt == NULL)
     838            0 :     return {};
     839              : 
     840         1268 :   *bitpos = fmt->signbit_rw;
     841         1268 :   if (*bitpos < 0)
     842            0 :     return {};
     843              : 
     844              :   /* Don't create negative zeros if the format doesn't support them.  */
     845         1268 :   if (op == neg_optab && !fmt->has_signed_zero)
     846            0 :     return {};
     847              : 
     848         1268 :   if (VECTOR_MODE_P (mode))
     849            3 :     return related_int_vector_mode (mode);
     850              : 
     851         2580 :   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     852         2496 :     return int_mode_for_mode (fmode);
     853              : 
     854           17 :   return word_mode;
     855              : }
     856              : 
     857              : /* Return true if we can implement OP for mode MODE directly, without resorting
     858              :    to a libfunc.   This usually means that OP will be implemented inline.
     859              : 
     860              :    Note that this function cannot tell whether the target pattern chooses to
     861              :    use libfuncs internally.  */
     862              : 
     863              : bool
     864      8005009 : can_open_code_p (optab op, machine_mode mode)
     865              : {
     866      8005009 :   if (optab_handler (op, mode) != CODE_FOR_nothing)
     867              :     return true;
     868              : 
     869      2374688 :   if (op == umul_highpart_optab)
     870          995 :     return can_mult_highpart_p (mode, true);
     871              : 
     872      2373693 :   if (op == smul_highpart_optab)
     873         1604 :     return can_mult_highpart_p (mode, false);
     874              : 
     875      2372089 :   machine_mode new_mode;
     876      2372089 :   scalar_float_mode fmode;
     877      2372089 :   int bitpos;
     878      2372089 :   if ((op == neg_optab || op == abs_optab)
     879         2676 :       && is_a<scalar_float_mode> (GET_MODE_INNER (mode), &fmode)
     880            4 :       && get_absneg_bit_mode (op, mode, fmode, &bitpos).exists (&new_mode)
     881      2372090 :       && can_open_code_p (op == neg_optab ? xor_optab : and_optab, new_mode))
     882            1 :     return true;
     883              : 
     884      2372088 :   scalar_int_mode int_mode;
     885      2372088 :   if (op == bswap_optab && is_a<scalar_int_mode> (mode, &int_mode))
     886              :     {
     887              :       /* widen_bswap_or_bitreverse can implement smaller bswaps using
     888              :          wider bswaps and a shift.  */
     889       138864 :       opt_scalar_int_mode wider_mode_iter;
     890       555456 :       FOR_EACH_WIDER_MODE (wider_mode_iter, int_mode)
     891       416592 :         if (optab_handler (op, wider_mode_iter.require ()) != CODE_FOR_nothing)
     892       138864 :           return true;
     893              : 
     894              :       /* expand_doubleword_bswap_or_bitreverse can use 2 word bswaps to
     895              :          implement a doubleword bswap.  */
     896       277728 :       if (GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD
     897       138864 :           && optab_handler (op, word_mode) != CODE_FOR_nothing)
     898              :         return true;
     899              :     }
     900              : 
     901              :   return false;
     902              : }
     903              : 
     904              : /* Return true if we can implement OP for mode MODE in some way, either by
     905              :    open-coding it or by calling a libfunc.  */
     906              : 
     907              : bool
     908      6229352 : can_implement_p (optab op, machine_mode mode)
     909              : {
     910      6229352 :   return can_open_code_p (op, mode) || optab_libfunc (op, mode);
     911              : }
        

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.