Home | History | Annotate | Line # | Download | only in d
intrinsics.cc revision 1.1.1.2
      1      1.1  mrg /* intrinsics.cc -- D language compiler intrinsics.
      2  1.1.1.2  mrg    Copyright (C) 2006-2020 Free Software Foundation, Inc.
      3      1.1  mrg 
      4      1.1  mrg GCC is free software; you can redistribute it and/or modify
      5      1.1  mrg it under the terms of the GNU General Public License as published by
      6      1.1  mrg the Free Software Foundation; either version 3, or (at your option)
      7      1.1  mrg any later version.
      8      1.1  mrg 
      9      1.1  mrg GCC is distributed in the hope that it will be useful,
     10      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     11      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12      1.1  mrg GNU General Public License for more details.
     13      1.1  mrg 
     14      1.1  mrg You should have received a copy of the GNU General Public License
     15      1.1  mrg along with GCC; see the file COPYING3.  If not see
     16      1.1  mrg <http://www.gnu.org/licenses/>.  */
     17      1.1  mrg 
     18      1.1  mrg #include "config.h"
     19      1.1  mrg #include "system.h"
     20      1.1  mrg #include "coretypes.h"
     21      1.1  mrg 
     22      1.1  mrg #include "dmd/declaration.h"
     23      1.1  mrg #include "dmd/identifier.h"
     24      1.1  mrg #include "dmd/mangle.h"
     25      1.1  mrg #include "dmd/mangle.h"
     26      1.1  mrg #include "dmd/module.h"
     27      1.1  mrg #include "dmd/template.h"
     28      1.1  mrg 
     29      1.1  mrg #include "tm.h"
     30      1.1  mrg #include "function.h"
     31      1.1  mrg #include "tree.h"
     32      1.1  mrg #include "fold-const.h"
     33      1.1  mrg #include "stringpool.h"
     34      1.1  mrg #include "builtins.h"
     35      1.1  mrg 
     36      1.1  mrg #include "d-tree.h"
     37      1.1  mrg 
     38      1.1  mrg 
     39      1.1  mrg /* An internal struct used to hold information on D intrinsics.  */
     40      1.1  mrg 
     41      1.1  mrg struct intrinsic_decl
     42      1.1  mrg {
     43      1.1  mrg   /* The DECL_FUNCTION_CODE of this decl.  */
     44      1.1  mrg   intrinsic_code code;
     45      1.1  mrg 
     46      1.1  mrg   /* The name of the intrinsic.  */
     47      1.1  mrg   const char *name;
     48      1.1  mrg 
     49      1.1  mrg   /* The module where the intrinsic is located.  */
     50      1.1  mrg   const char *module;
     51      1.1  mrg 
     52      1.1  mrg   /* The mangled signature decoration of the intrinsic.  */
     53      1.1  mrg   const char *deco;
     54      1.1  mrg 
     55      1.1  mrg   /* True if the intrinsic is only handled in CTFE.  */
     56      1.1  mrg   bool ctfeonly;
     57      1.1  mrg };
     58      1.1  mrg 
     59      1.1  mrg static const intrinsic_decl intrinsic_decls[] =
     60      1.1  mrg {
     61      1.1  mrg #define DEF_D_INTRINSIC(CODE, ALIAS, NAME, MODULE, DECO, CTFE) \
     62      1.1  mrg     { INTRINSIC_ ## ALIAS, NAME, MODULE, DECO, CTFE },
     63      1.1  mrg 
     64      1.1  mrg #include "intrinsics.def"
     65      1.1  mrg 
     66      1.1  mrg #undef DEF_D_INTRINSIC
     67      1.1  mrg };
     68      1.1  mrg 
     69      1.1  mrg /* Checks if DECL is an intrinsic or run time library function that requires
     70      1.1  mrg    special processing.  Sets DECL_INTRINSIC_CODE so it can be identified
     71      1.1  mrg    later in maybe_expand_intrinsic.  */
     72      1.1  mrg 
     73      1.1  mrg void
     74      1.1  mrg maybe_set_intrinsic (FuncDeclaration *decl)
     75      1.1  mrg {
     76      1.1  mrg   if (!decl->ident || decl->builtin != BUILTINunknown)
     77      1.1  mrg     return;
     78      1.1  mrg 
     79      1.1  mrg   /* The builtin flag is updated only if we can evaluate the intrinsic
     80      1.1  mrg      at compile-time.  Such as the math or bitop intrinsics.  */
     81      1.1  mrg   decl->builtin = BUILTINno;
     82      1.1  mrg 
     83      1.1  mrg   /* Check if it's a compiler intrinsic.  We only require that any
     84      1.1  mrg      internally recognised intrinsics are declared in a module with
     85      1.1  mrg      an explicit module declaration.  */
     86      1.1  mrg   Module *m = decl->getModule ();
     87      1.1  mrg 
     88      1.1  mrg   if (!m || !m->md)
     89      1.1  mrg     return;
     90      1.1  mrg 
     91      1.1  mrg   TemplateInstance *ti = decl->isInstantiated ();
     92      1.1  mrg   TemplateDeclaration *td = ti ? ti->tempdecl->isTemplateDeclaration () : NULL;
     93      1.1  mrg 
     94      1.1  mrg   const char *tname = decl->ident->toChars ();
     95      1.1  mrg   const char *tmodule = m->md->toChars ();
     96      1.1  mrg   const char *tdeco = (td == NULL) ? decl->type->deco : NULL;
     97      1.1  mrg 
     98      1.1  mrg   /* Look through all D intrinsics.  */
     99      1.1  mrg   for (size_t i = 0; i < (int) INTRINSIC_LAST; i++)
    100      1.1  mrg     {
    101      1.1  mrg       if (!intrinsic_decls[i].name)
    102      1.1  mrg 	continue;
    103      1.1  mrg 
    104      1.1  mrg       if (strcmp (intrinsic_decls[i].name, tname) != 0
    105      1.1  mrg 	  || strcmp (intrinsic_decls[i].module, tmodule) != 0)
    106      1.1  mrg 	continue;
    107      1.1  mrg 
    108      1.1  mrg       /* Instantiated functions would have the wrong type deco, get it from the
    109      1.1  mrg 	 template member instead.  */
    110      1.1  mrg       if (tdeco == NULL)
    111      1.1  mrg 	{
    112      1.1  mrg 	  if (!td || !td->onemember)
    113      1.1  mrg 	    return;
    114      1.1  mrg 
    115      1.1  mrg 	  FuncDeclaration *fd = td->onemember->isFuncDeclaration ();
    116      1.1  mrg 	  if (fd == NULL)
    117      1.1  mrg 	    return;
    118      1.1  mrg 
    119      1.1  mrg 	  OutBuffer buf;
    120      1.1  mrg 	  mangleToBuffer (fd->type, &buf);
    121      1.1  mrg 	  tdeco = buf.extractString ();
    122      1.1  mrg 	}
    123      1.1  mrg 
    124      1.1  mrg       /* Matching the type deco may be a bit too strict, as it means that all
    125      1.1  mrg 	 function attributes that end up in the signature must be kept aligned
    126      1.1  mrg 	 between the compiler and library declaration.  */
    127      1.1  mrg       if (strcmp (intrinsic_decls[i].deco, tdeco) == 0)
    128      1.1  mrg 	{
    129      1.1  mrg 	  intrinsic_code code = intrinsic_decls[i].code;
    130      1.1  mrg 
    131      1.1  mrg 	  if (decl->csym == NULL)
    132      1.1  mrg 	    get_symbol_decl (decl);
    133      1.1  mrg 
    134      1.1  mrg 	  /* If there is no function body, then the implementation is always
    135      1.1  mrg 	     provided by the compiler.  */
    136      1.1  mrg 	  if (!decl->fbody)
    137  1.1.1.2  mrg 	    set_decl_built_in_function (decl->csym, BUILT_IN_FRONTEND, code);
    138      1.1  mrg 
    139      1.1  mrg 	  /* Infer whether the intrinsic can be used for CTFE, let the
    140      1.1  mrg 	     front-end know that it can be evaluated at compile-time.  */
    141      1.1  mrg 	  switch (code)
    142      1.1  mrg 	    {
    143      1.1  mrg 	    case INTRINSIC_VA_ARG:
    144      1.1  mrg 	    case INTRINSIC_C_VA_ARG:
    145      1.1  mrg 	    case INTRINSIC_VASTART:
    146      1.1  mrg 	    case INTRINSIC_ADDS:
    147      1.1  mrg 	    case INTRINSIC_SUBS:
    148      1.1  mrg 	    case INTRINSIC_MULS:
    149      1.1  mrg 	    case INTRINSIC_NEGS:
    150      1.1  mrg 	    case INTRINSIC_VLOAD:
    151      1.1  mrg 	    case INTRINSIC_VSTORE:
    152      1.1  mrg 	      break;
    153      1.1  mrg 
    154      1.1  mrg 	    case INTRINSIC_POW:
    155      1.1  mrg 	    {
    156      1.1  mrg 	      /* Check that this overload of pow() is has an equivalent
    157      1.1  mrg 		 built-in function.  It could be `int pow(int, int)'.  */
    158      1.1  mrg 	      tree rettype = TREE_TYPE (TREE_TYPE (decl->csym));
    159      1.1  mrg 	      if (mathfn_built_in (rettype, BUILT_IN_POW) != NULL_TREE)
    160      1.1  mrg 		decl->builtin = BUILTINyes;
    161      1.1  mrg 	      break;
    162      1.1  mrg 	    }
    163      1.1  mrg 
    164      1.1  mrg 	    default:
    165      1.1  mrg 	      decl->builtin = BUILTINyes;
    166      1.1  mrg 	      break;
    167      1.1  mrg 	    }
    168      1.1  mrg 
    169      1.1  mrg 	  /* The intrinsic was marked as CTFE-only.  */
    170      1.1  mrg 	  if (intrinsic_decls[i].ctfeonly)
    171      1.1  mrg 	    DECL_BUILT_IN_CTFE (decl->csym) = 1;
    172      1.1  mrg 
    173      1.1  mrg 	  DECL_INTRINSIC_CODE (decl->csym) = code;
    174      1.1  mrg 	  break;
    175      1.1  mrg 	}
    176      1.1  mrg     }
    177      1.1  mrg }
    178      1.1  mrg 
    179      1.1  mrg /* Construct a function call to the built-in function CODE, N is the number of
    180      1.1  mrg    arguments, and the `...' parameters are the argument expressions.
    181      1.1  mrg    The original call expression is held in CALLEXP.  */
    182      1.1  mrg 
    183      1.1  mrg static tree
    184      1.1  mrg call_builtin_fn (tree callexp, built_in_function code, int n, ...)
    185      1.1  mrg {
    186      1.1  mrg   tree *argarray = XALLOCAVEC (tree, n);
    187      1.1  mrg   va_list ap;
    188      1.1  mrg 
    189      1.1  mrg   va_start (ap, n);
    190      1.1  mrg   for (int i = 0; i < n; i++)
    191      1.1  mrg     argarray[i] = va_arg (ap, tree);
    192      1.1  mrg   va_end (ap);
    193      1.1  mrg 
    194      1.1  mrg   tree exp = build_call_expr_loc_array (EXPR_LOCATION (callexp),
    195      1.1  mrg 					builtin_decl_explicit (code),
    196      1.1  mrg 					n, argarray);
    197      1.1  mrg   return convert (TREE_TYPE (callexp), fold (exp));
    198      1.1  mrg }
    199      1.1  mrg 
    200      1.1  mrg /* Expand a front-end instrinsic call to bsf().  This takes one argument,
    201      1.1  mrg    the signature to which can be either:
    202      1.1  mrg 
    203      1.1  mrg 	int bsf (uint arg);
    204      1.1  mrg 	int bsf (ulong arg);
    205      1.1  mrg 
    206      1.1  mrg    This scans all bits in the given argument starting with the first,
    207      1.1  mrg    returning the bit number of the first bit set.  The original call
    208      1.1  mrg    expression is held in CALLEXP.  */
    209      1.1  mrg 
    210      1.1  mrg static tree
    211      1.1  mrg expand_intrinsic_bsf (tree callexp)
    212      1.1  mrg {
    213      1.1  mrg   /* The bsr() intrinsic gets turned into __builtin_ctz(arg).
    214      1.1  mrg      The return value is supposed to be undefined if arg is zero.  */
    215      1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    216      1.1  mrg   int argsize = TYPE_PRECISION (TREE_TYPE (arg));
    217      1.1  mrg 
    218      1.1  mrg   /* Which variant of __builtin_ctz* should we call?  */
    219      1.1  mrg   built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CTZ
    220      1.1  mrg     : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CTZL
    221      1.1  mrg     : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CTZLL
    222      1.1  mrg     : END_BUILTINS;
    223      1.1  mrg 
    224      1.1  mrg   gcc_assert (code != END_BUILTINS);
    225      1.1  mrg 
    226      1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    227      1.1  mrg }
    228      1.1  mrg 
    229      1.1  mrg /* Expand a front-end instrinsic call to bsr().  This takes one argument,
    230      1.1  mrg    the signature to which can be either:
    231      1.1  mrg 
    232      1.1  mrg 	int bsr (uint arg);
    233      1.1  mrg 	int bsr (ulong arg);
    234      1.1  mrg 
    235      1.1  mrg    This scans all bits in the given argument from the most significant bit
    236      1.1  mrg    to the least significant, returning the bit number of the first bit set.
    237      1.1  mrg    The original call expression is held in CALLEXP.  */
    238      1.1  mrg 
    239      1.1  mrg static tree
    240      1.1  mrg expand_intrinsic_bsr (tree callexp)
    241      1.1  mrg {
    242      1.1  mrg   /* The bsr() intrinsic gets turned into (size - 1) - __builtin_clz(arg).
    243      1.1  mrg      The return value is supposed to be undefined if arg is zero.  */
    244      1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    245      1.1  mrg   tree type = TREE_TYPE (arg);
    246      1.1  mrg   int argsize = TYPE_PRECISION (type);
    247      1.1  mrg 
    248      1.1  mrg   /* Which variant of __builtin_clz* should we call?  */
    249      1.1  mrg   built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CLZ
    250      1.1  mrg     : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CLZL
    251      1.1  mrg     : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CLZLL
    252      1.1  mrg     : END_BUILTINS;
    253      1.1  mrg 
    254      1.1  mrg   gcc_assert (code != END_BUILTINS);
    255      1.1  mrg 
    256      1.1  mrg   tree result = call_builtin_fn (callexp, code, 1, arg);
    257      1.1  mrg 
    258      1.1  mrg   /* Handle int -> long conversions.  */
    259      1.1  mrg   if (TREE_TYPE (result) != type)
    260      1.1  mrg     result = fold_convert (type, result);
    261      1.1  mrg 
    262      1.1  mrg   result = fold_build2 (MINUS_EXPR, type,
    263      1.1  mrg 			build_integer_cst (argsize - 1, type), result);
    264      1.1  mrg   return fold_convert (TREE_TYPE (callexp), result);
    265      1.1  mrg }
    266      1.1  mrg 
    267      1.1  mrg /* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
    268      1.1  mrg    bt(), btc(), btr(), or bts().  These intrinsics expect to take two arguments,
    269      1.1  mrg    the signature to which is:
    270      1.1  mrg 
    271      1.1  mrg 	int bt (size_t* ptr, size_t bitnum);
    272      1.1  mrg 
    273      1.1  mrg    All intrinsics test if a bit is set and return the result of that condition.
    274      1.1  mrg    Variants of `bt' will then update that bit. `btc' compliments the bit, `bts'
    275      1.1  mrg    sets the bit, and `btr' resets the bit.  The original call expression is
    276      1.1  mrg    held in CALLEXP.  */
    277      1.1  mrg 
    278      1.1  mrg static tree
    279      1.1  mrg expand_intrinsic_bt (intrinsic_code intrinsic, tree callexp)
    280      1.1  mrg {
    281      1.1  mrg   tree ptr = CALL_EXPR_ARG (callexp, 0);
    282      1.1  mrg   tree bitnum = CALL_EXPR_ARG (callexp, 1);
    283      1.1  mrg   tree type = TREE_TYPE (TREE_TYPE (ptr));
    284      1.1  mrg 
    285      1.1  mrg   /* size_t bitsize = sizeof(*ptr) * BITS_PER_UNIT;  */
    286      1.1  mrg   tree bitsize = fold_convert (type, TYPE_SIZE (type));
    287      1.1  mrg 
    288      1.1  mrg   /* ptr[bitnum / bitsize]  */
    289      1.1  mrg   ptr = build_array_index (ptr, fold_build2 (TRUNC_DIV_EXPR, type,
    290      1.1  mrg 					     bitnum, bitsize));
    291      1.1  mrg   ptr = indirect_ref (type, ptr);
    292      1.1  mrg 
    293      1.1  mrg   /* mask = 1 << (bitnum % bitsize);  */
    294      1.1  mrg   bitnum = fold_build2 (TRUNC_MOD_EXPR, type, bitnum, bitsize);
    295      1.1  mrg   bitnum = fold_build2 (LSHIFT_EXPR, type, size_one_node, bitnum);
    296      1.1  mrg 
    297      1.1  mrg   /* cond = ptr[bitnum / size] & mask;  */
    298      1.1  mrg   tree cond = fold_build2 (BIT_AND_EXPR, type, ptr, bitnum);
    299      1.1  mrg 
    300      1.1  mrg   /* cond ? -1 : 0;  */
    301      1.1  mrg   cond = build_condition (TREE_TYPE (callexp), d_truthvalue_conversion (cond),
    302      1.1  mrg 			 integer_minus_one_node, integer_zero_node);
    303      1.1  mrg 
    304      1.1  mrg   /* Update the bit as needed, only testing the bit for bt().  */
    305      1.1  mrg   if (intrinsic == INTRINSIC_BT)
    306      1.1  mrg     return cond;
    307      1.1  mrg 
    308      1.1  mrg   tree_code code = (intrinsic == INTRINSIC_BTC) ? BIT_XOR_EXPR
    309      1.1  mrg     : (intrinsic == INTRINSIC_BTR) ? BIT_AND_EXPR
    310      1.1  mrg     : (intrinsic == INTRINSIC_BTS) ? BIT_IOR_EXPR
    311      1.1  mrg     : ERROR_MARK;
    312      1.1  mrg   gcc_assert (code != ERROR_MARK);
    313      1.1  mrg 
    314      1.1  mrg   /* ptr[bitnum / size] op= mask;  */
    315      1.1  mrg   if (intrinsic == INTRINSIC_BTR)
    316      1.1  mrg     bitnum = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (bitnum), bitnum);
    317      1.1  mrg 
    318      1.1  mrg   ptr = modify_expr (ptr, fold_build2 (code, TREE_TYPE (ptr), ptr, bitnum));
    319      1.1  mrg 
    320      1.1  mrg   /* Store the condition result in a temporary, and return expressions in
    321      1.1  mrg      correct order of evaluation.  */
    322      1.1  mrg   tree tmp = build_local_temp (TREE_TYPE (callexp));
    323      1.1  mrg   cond = modify_expr (tmp, cond);
    324      1.1  mrg 
    325      1.1  mrg   return compound_expr (cond, compound_expr (ptr, tmp));
    326      1.1  mrg }
    327      1.1  mrg 
    328      1.1  mrg /* Expand a front-end intrinsic call to bswap().  This takes one argument, the
    329      1.1  mrg    signature to which can be either:
    330      1.1  mrg 
    331      1.1  mrg 	int bswap (uint arg);
    332      1.1  mrg 	int bswap (ulong arg);
    333      1.1  mrg 
    334      1.1  mrg    This swaps all bytes in an N byte type end-to-end.  The original call
    335      1.1  mrg    expression is held in CALLEXP.  */
    336      1.1  mrg 
    337      1.1  mrg static tree
    338      1.1  mrg expand_intrinsic_bswap (tree callexp)
    339      1.1  mrg {
    340      1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    341      1.1  mrg   int argsize = TYPE_PRECISION (TREE_TYPE (arg));
    342      1.1  mrg 
    343      1.1  mrg   /* Which variant of __builtin_bswap* should we call?  */
    344      1.1  mrg   built_in_function code = (argsize == 32) ? BUILT_IN_BSWAP32
    345      1.1  mrg     : (argsize == 64) ? BUILT_IN_BSWAP64
    346      1.1  mrg     : END_BUILTINS;
    347      1.1  mrg 
    348      1.1  mrg   gcc_assert (code != END_BUILTINS);
    349      1.1  mrg 
    350      1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    351      1.1  mrg }
    352      1.1  mrg 
    353      1.1  mrg /* Expand a front-end intrinsic call to popcnt().  This takes one argument, the
    354      1.1  mrg    signature to which can be either:
    355      1.1  mrg 
    356      1.1  mrg 	int popcnt (uint arg);
    357      1.1  mrg 	int popcnt (ulong arg);
    358      1.1  mrg 
    359      1.1  mrg    Calculates the number of set bits in an integer.  The original call
    360      1.1  mrg    expression is held in CALLEXP.  */
    361      1.1  mrg 
    362      1.1  mrg static tree
    363      1.1  mrg expand_intrinsic_popcnt (tree callexp)
    364      1.1  mrg {
    365      1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    366      1.1  mrg   int argsize = TYPE_PRECISION (TREE_TYPE (arg));
    367      1.1  mrg 
    368      1.1  mrg   /* Which variant of __builtin_popcount* should we call?  */
    369      1.1  mrg   built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_POPCOUNT
    370      1.1  mrg     : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTL
    371      1.1  mrg     : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTLL
    372      1.1  mrg     : END_BUILTINS;
    373      1.1  mrg 
    374      1.1  mrg   gcc_assert (code != END_BUILTINS);
    375      1.1  mrg 
    376      1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    377      1.1  mrg }
    378      1.1  mrg 
    379      1.1  mrg /* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
    380      1.1  mrg    sqrt(), sqrtf(), sqrtl().  These intrinsics expect to take one argument,
    381      1.1  mrg    the signature to which can be either:
    382      1.1  mrg 
    383      1.1  mrg 	float sqrt (float arg);
    384      1.1  mrg 	double sqrt (double arg);
    385      1.1  mrg 	real sqrt (real arg);
    386      1.1  mrg 
    387      1.1  mrg    This computes the square root of the given argument.  The original call
    388      1.1  mrg    expression is held in CALLEXP.  */
    389      1.1  mrg 
    390      1.1  mrg static tree
    391      1.1  mrg expand_intrinsic_sqrt (intrinsic_code intrinsic, tree callexp)
    392      1.1  mrg {
    393      1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    394      1.1  mrg 
    395      1.1  mrg   /* Which variant of __builtin_sqrt* should we call?  */
    396      1.1  mrg   built_in_function code = (intrinsic == INTRINSIC_SQRT) ? BUILT_IN_SQRT
    397      1.1  mrg     : (intrinsic == INTRINSIC_SQRTF) ? BUILT_IN_SQRTF
    398      1.1  mrg     : (intrinsic == INTRINSIC_SQRTL) ? BUILT_IN_SQRTL
    399      1.1  mrg     : END_BUILTINS;
    400      1.1  mrg 
    401      1.1  mrg   gcc_assert (code != END_BUILTINS);
    402      1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    403      1.1  mrg }
    404      1.1  mrg 
    405      1.1  mrg /* Expand a front-end intrinsic call to copysign().  This takes two arguments,
    406      1.1  mrg    the signature to which can be either:
    407      1.1  mrg 
    408      1.1  mrg 	float copysign (T to, float from);
    409      1.1  mrg 	double copysign (T to, double from);
    410      1.1  mrg 	real copysign (T to, real from);
    411      1.1  mrg 
    412      1.1  mrg    This computes a value composed of TO with the sign bit of FROM.  The original
    413      1.1  mrg    call expression is held in CALLEXP.  */
    414      1.1  mrg 
    415      1.1  mrg static tree
    416      1.1  mrg expand_intrinsic_copysign (tree callexp)
    417      1.1  mrg {
    418      1.1  mrg   tree to = CALL_EXPR_ARG (callexp, 0);
    419      1.1  mrg   tree from = CALL_EXPR_ARG (callexp, 1);
    420      1.1  mrg   tree type = TREE_TYPE (to);
    421      1.1  mrg 
    422      1.1  mrg   /* Convert parameters to the same type.  Prefer the first parameter unless it
    423      1.1  mrg      is an integral type.  */
    424      1.1  mrg   if (INTEGRAL_TYPE_P (type))
    425      1.1  mrg     {
    426      1.1  mrg       to = fold_convert (TREE_TYPE (from), to);
    427      1.1  mrg       type = TREE_TYPE (to);
    428      1.1  mrg     }
    429      1.1  mrg   else
    430      1.1  mrg     from = fold_convert (type, from);
    431      1.1  mrg 
    432      1.1  mrg   /* Which variant of __builtin_copysign* should we call?  */
    433  1.1.1.2  mrg   built_in_function code = (type == float_type_node) ? BUILT_IN_COPYSIGNF
    434  1.1.1.2  mrg     : (type == double_type_node) ? BUILT_IN_COPYSIGN
    435  1.1.1.2  mrg     : (type == long_double_type_node) ? BUILT_IN_COPYSIGNL
    436  1.1.1.2  mrg     : END_BUILTINS;
    437      1.1  mrg 
    438  1.1.1.2  mrg   gcc_assert (code != END_BUILTINS);
    439  1.1.1.2  mrg 
    440  1.1.1.2  mrg   return call_builtin_fn (callexp, code, 2, to, from);
    441      1.1  mrg }
    442      1.1  mrg 
    443      1.1  mrg /* Expand a front-end intrinsic call to pow().  This takes two arguments, the
    444      1.1  mrg    signature to which can be either:
    445      1.1  mrg 
    446      1.1  mrg 	float pow (float base, T exponent);
    447      1.1  mrg 	double pow (double base, T exponent);
    448      1.1  mrg 	real pow (real base, T exponent);
    449      1.1  mrg 
    450      1.1  mrg    This computes the value of BASE raised to the power of EXPONENT.
    451      1.1  mrg    The original call expression is held in CALLEXP.  */
    452      1.1  mrg 
    453      1.1  mrg static tree
    454      1.1  mrg expand_intrinsic_pow (tree callexp)
    455      1.1  mrg {
    456      1.1  mrg   tree base = CALL_EXPR_ARG (callexp, 0);
    457      1.1  mrg   tree exponent = CALL_EXPR_ARG (callexp, 1);
    458      1.1  mrg   tree exptype = TREE_TYPE (exponent);
    459      1.1  mrg 
    460      1.1  mrg   /* Which variant of __builtin_pow* should we call?  */
    461      1.1  mrg   built_in_function code = SCALAR_FLOAT_TYPE_P (exptype) ? BUILT_IN_POW
    462      1.1  mrg     : INTEGRAL_TYPE_P (exptype) ? BUILT_IN_POWI
    463      1.1  mrg     : END_BUILTINS;
    464      1.1  mrg   gcc_assert (code != END_BUILTINS);
    465      1.1  mrg 
    466      1.1  mrg   tree builtin = mathfn_built_in (TREE_TYPE (base), code);
    467      1.1  mrg   gcc_assert (builtin != NULL_TREE);
    468      1.1  mrg 
    469      1.1  mrg   return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2,
    470      1.1  mrg 			  base, exponent);
    471      1.1  mrg }
    472      1.1  mrg 
    473  1.1.1.2  mrg /* Expand a front-end intrinsic call to toPrec().  This takes one argument, the
    474  1.1.1.2  mrg    signature to which can be either:
    475  1.1.1.2  mrg 
    476  1.1.1.2  mrg 	T toPrec(T)(float f);
    477  1.1.1.2  mrg 	T toPrec(T)(double f);
    478  1.1.1.2  mrg 	T toPrec(T)(real f);
    479  1.1.1.2  mrg 
    480  1.1.1.2  mrg     This rounds the argument F to the precision of the specified floating
    481  1.1.1.2  mrg     point type T.  The original call expression is held in CALLEXP.  */
    482  1.1.1.2  mrg 
    483  1.1.1.2  mrg static tree
    484  1.1.1.2  mrg expand_intrinsic_toprec (tree callexp)
    485  1.1.1.2  mrg {
    486  1.1.1.2  mrg   tree f = CALL_EXPR_ARG (callexp, 0);
    487  1.1.1.2  mrg   tree type = TREE_TYPE (callexp);
    488  1.1.1.2  mrg 
    489  1.1.1.2  mrg   return convert (type, f);
    490  1.1.1.2  mrg }
    491  1.1.1.2  mrg 
    492      1.1  mrg /* Expand a front-end intrinsic call to va_arg().  This takes either one or two
    493      1.1  mrg    arguments, the signature to which can be either:
    494      1.1  mrg 
    495      1.1  mrg 	T va_arg(T) (ref va_list ap);
    496      1.1  mrg 	void va_arg(T) (va_list ap, ref T parmn);
    497      1.1  mrg 
    498      1.1  mrg    This retrieves the next variadic parameter that is type T from the given
    499      1.1  mrg    va_list.  If also given, store the value into parmn, otherwise return it.
    500      1.1  mrg    The original call expression is held in CALLEXP.  */
    501      1.1  mrg 
    502      1.1  mrg static tree
    503      1.1  mrg expand_intrinsic_vaarg (tree callexp)
    504      1.1  mrg {
    505      1.1  mrg   tree ap = CALL_EXPR_ARG (callexp, 0);
    506      1.1  mrg   tree parmn = NULL_TREE;
    507      1.1  mrg   tree type;
    508      1.1  mrg 
    509      1.1  mrg   STRIP_NOPS (ap);
    510      1.1  mrg 
    511      1.1  mrg   if (call_expr_nargs (callexp) == 1)
    512      1.1  mrg     type = TREE_TYPE (callexp);
    513      1.1  mrg   else
    514      1.1  mrg     {
    515      1.1  mrg       parmn = CALL_EXPR_ARG (callexp, 1);
    516      1.1  mrg       STRIP_NOPS (parmn);
    517  1.1.1.2  mrg 
    518  1.1.1.2  mrg       /* The `ref' argument to va_arg is either an address or reference,
    519  1.1.1.2  mrg 	 get the value of it.  */
    520  1.1.1.2  mrg       if (TREE_CODE (parmn) == PARM_DECL && POINTER_TYPE_P (TREE_TYPE (parmn)))
    521  1.1.1.2  mrg 	parmn = build_deref (parmn);
    522  1.1.1.2  mrg       else
    523  1.1.1.2  mrg 	{
    524  1.1.1.2  mrg 	  gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
    525  1.1.1.2  mrg 	  parmn = TREE_OPERAND (parmn, 0);
    526  1.1.1.2  mrg 	}
    527  1.1.1.2  mrg 
    528      1.1  mrg       type = TREE_TYPE (parmn);
    529      1.1  mrg     }
    530      1.1  mrg 
    531      1.1  mrg   /* (T) VA_ARG_EXP<ap>;  */
    532      1.1  mrg   tree exp = build1 (VA_ARG_EXPR, type, ap);
    533      1.1  mrg 
    534      1.1  mrg   /* parmn = (T) VA_ARG_EXP<ap>;  */
    535      1.1  mrg   if (parmn != NULL_TREE)
    536      1.1  mrg     exp = modify_expr (parmn, exp);
    537      1.1  mrg 
    538      1.1  mrg   return exp;
    539      1.1  mrg }
    540      1.1  mrg 
    541      1.1  mrg /* Expand a front-end intrinsic call to va_start(), which takes two arguments,
    542      1.1  mrg    the signature to which is:
    543      1.1  mrg 
    544      1.1  mrg 	void va_start(T) (out va_list ap, ref T parmn);
    545      1.1  mrg 
    546      1.1  mrg    This initializes the va_list type, where parmn should be the last named
    547      1.1  mrg    parameter.  The original call expression is held in CALLEXP.  */
    548      1.1  mrg 
    549      1.1  mrg static tree
    550      1.1  mrg expand_intrinsic_vastart (tree callexp)
    551      1.1  mrg {
    552      1.1  mrg   tree ap = CALL_EXPR_ARG (callexp, 0);
    553      1.1  mrg   tree parmn = CALL_EXPR_ARG (callexp, 1);
    554      1.1  mrg 
    555      1.1  mrg   STRIP_NOPS (ap);
    556      1.1  mrg   STRIP_NOPS (parmn);
    557      1.1  mrg 
    558      1.1  mrg   /* The va_list argument should already have its address taken.  The second
    559      1.1  mrg      argument, however, is inout and that needs to be fixed to prevent a
    560      1.1  mrg      warning.  Could be casting, so need to check type too?  */
    561  1.1.1.2  mrg   gcc_assert (TREE_CODE (ap) == ADDR_EXPR
    562  1.1.1.2  mrg 	      || (TREE_CODE (ap) == PARM_DECL
    563  1.1.1.2  mrg 		  && POINTER_TYPE_P (TREE_TYPE (ap))));
    564      1.1  mrg 
    565      1.1  mrg   /* Assuming nobody tries to change the return type.  */
    566  1.1.1.2  mrg   if (TREE_CODE (parmn) != PARM_DECL)
    567  1.1.1.2  mrg     {
    568  1.1.1.2  mrg       gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
    569  1.1.1.2  mrg       parmn = TREE_OPERAND (parmn, 0);
    570  1.1.1.2  mrg     }
    571      1.1  mrg 
    572      1.1  mrg   return call_builtin_fn (callexp, BUILT_IN_VA_START, 2, ap, parmn);
    573      1.1  mrg }
    574      1.1  mrg 
    575      1.1  mrg /* Expand a front-end instrinsic call to INTRINSIC, which is either a call to
    576      1.1  mrg    adds(), addu(), subs(), subu(), negs(), muls(), or mulu().  These intrinsics
    577      1.1  mrg    expect to take two or three arguments, the signature to which can be either:
    578      1.1  mrg 
    579      1.1  mrg 	int adds (int x, int y, ref bool overflow);
    580      1.1  mrg 	long adds (long x, long y, ref bool overflow);
    581      1.1  mrg 	int negs (int x, ref bool overflow);
    582      1.1  mrg 	long negs (long x, ref bool overflow);
    583      1.1  mrg 
    584      1.1  mrg    This performs an operation on two signed or unsigned integers, checking for
    585      1.1  mrg    overflow.  The overflow is sticky, meaning that a sequence of operations
    586      1.1  mrg    can be done and overflow need only be checked at the end.  The original call
    587      1.1  mrg    expression is held in CALLEXP.  */
    588      1.1  mrg 
    589      1.1  mrg static tree
    590      1.1  mrg expand_intrinsic_checkedint (intrinsic_code intrinsic, tree callexp)
    591      1.1  mrg {
    592      1.1  mrg   tree type = TREE_TYPE (callexp);
    593      1.1  mrg   tree x;
    594      1.1  mrg   tree y;
    595      1.1  mrg   tree overflow;
    596      1.1  mrg 
    597      1.1  mrg   /* The negs() intrinsic gets turned into SUB_OVERFLOW (0, y).  */
    598      1.1  mrg   if (intrinsic == INTRINSIC_NEGS)
    599      1.1  mrg     {
    600      1.1  mrg       x = fold_convert (type, integer_zero_node);
    601      1.1  mrg       y = CALL_EXPR_ARG (callexp, 0);
    602      1.1  mrg       overflow = CALL_EXPR_ARG (callexp, 1);
    603      1.1  mrg     }
    604      1.1  mrg   else
    605      1.1  mrg     {
    606      1.1  mrg       x = CALL_EXPR_ARG (callexp, 0);
    607      1.1  mrg       y = CALL_EXPR_ARG (callexp, 1);
    608      1.1  mrg       overflow = CALL_EXPR_ARG (callexp, 2);
    609      1.1  mrg     }
    610      1.1  mrg 
    611      1.1  mrg   /* Which variant of *_OVERFLOW should we generate?  */
    612      1.1  mrg   internal_fn icode = (intrinsic == INTRINSIC_ADDS) ? IFN_ADD_OVERFLOW
    613      1.1  mrg     : (intrinsic == INTRINSIC_SUBS) ? IFN_SUB_OVERFLOW
    614      1.1  mrg     : (intrinsic == INTRINSIC_MULS) ? IFN_MUL_OVERFLOW
    615      1.1  mrg     : (intrinsic == INTRINSIC_NEGS) ? IFN_SUB_OVERFLOW
    616      1.1  mrg     : IFN_LAST;
    617      1.1  mrg   gcc_assert (icode != IFN_LAST);
    618      1.1  mrg 
    619      1.1  mrg   tree result
    620      1.1  mrg     = build_call_expr_internal_loc (EXPR_LOCATION (callexp), icode,
    621      1.1  mrg 				    build_complex_type (type), 2, x, y);
    622      1.1  mrg 
    623      1.1  mrg   STRIP_NOPS (overflow);
    624      1.1  mrg   overflow = build_deref (overflow);
    625      1.1  mrg 
    626      1.1  mrg   /* Assign returned result to overflow parameter, however if overflow is
    627      1.1  mrg      already true, maintain its value.  */
    628      1.1  mrg   type = TREE_TYPE (overflow);
    629      1.1  mrg   result = save_expr (result);
    630      1.1  mrg 
    631      1.1  mrg   tree exp = fold_build2 (BIT_IOR_EXPR, type, overflow,
    632      1.1  mrg 			  fold_convert (type, imaginary_part (result)));
    633      1.1  mrg   exp = modify_expr (overflow, exp);
    634      1.1  mrg 
    635      1.1  mrg   /* Return the value of result.  */
    636      1.1  mrg   return compound_expr (exp, real_part (result));
    637      1.1  mrg }
    638      1.1  mrg 
    639      1.1  mrg /* Expand a front-end instrinsic call to volatileLoad().  This takes one
    640      1.1  mrg    argument, the signature to which can be either:
    641      1.1  mrg 
    642      1.1  mrg 	ubyte volatileLoad (ubyte* ptr);
    643      1.1  mrg 	ushort volatileLoad (ushort* ptr);
    644      1.1  mrg 	uint volatileLoad (uint* ptr);
    645      1.1  mrg 	ulong volatileLoad (ulong* ptr);
    646      1.1  mrg 
    647      1.1  mrg    This reads a value from the memory location indicated by ptr.  Calls to
    648      1.1  mrg    them are be guaranteed to not be removed (such as during DCE) or reordered
    649      1.1  mrg    in the same thread.  The original call expression is held in CALLEXP.  */
    650      1.1  mrg 
    651      1.1  mrg static tree
    652      1.1  mrg expand_volatile_load (tree callexp)
    653      1.1  mrg {
    654      1.1  mrg   tree ptr = CALL_EXPR_ARG (callexp, 0);
    655      1.1  mrg   tree ptrtype = TREE_TYPE (ptr);
    656      1.1  mrg   gcc_assert (POINTER_TYPE_P (ptrtype));
    657      1.1  mrg 
    658      1.1  mrg   /* (T) *(volatile T *) ptr;  */
    659      1.1  mrg   tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
    660      1.1  mrg   tree result = indirect_ref (type, ptr);
    661      1.1  mrg   TREE_THIS_VOLATILE (result) = 1;
    662      1.1  mrg 
    663      1.1  mrg   return result;
    664      1.1  mrg }
    665      1.1  mrg 
    666      1.1  mrg /* Expand a front-end instrinsic call to volatileStore().  This takes two
    667      1.1  mrg    arguments, the signature to which can be either:
    668      1.1  mrg 
    669      1.1  mrg 	void volatileStore (ubyte* ptr, ubyte value);
    670      1.1  mrg 	void volatileStore (ushort* ptr, ushort value);
    671      1.1  mrg 	void volatileStore (uint* ptr, uint value);
    672      1.1  mrg 	void volatileStore (ulong* ptr, ulong value);
    673      1.1  mrg 
    674      1.1  mrg    This writes a value to the memory location indicated by ptr.  Calls to
    675      1.1  mrg    them are be guaranteed to not be removed (such as during DCE) or reordered
    676      1.1  mrg    in the same thread.  The original call expression is held in CALLEXP.  */
    677      1.1  mrg 
    678      1.1  mrg static tree
    679      1.1  mrg expand_volatile_store (tree callexp)
    680      1.1  mrg {
    681      1.1  mrg   tree ptr = CALL_EXPR_ARG (callexp, 0);
    682      1.1  mrg   tree ptrtype = TREE_TYPE (ptr);
    683      1.1  mrg   gcc_assert (POINTER_TYPE_P (ptrtype));
    684      1.1  mrg 
    685      1.1  mrg   /* (T) *(volatile T *) ptr;  */
    686      1.1  mrg   tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
    687      1.1  mrg   tree result = indirect_ref (type, ptr);
    688      1.1  mrg   TREE_THIS_VOLATILE (result) = 1;
    689      1.1  mrg 
    690      1.1  mrg   /* (*(volatile T *) ptr) = value;  */
    691      1.1  mrg   tree value = CALL_EXPR_ARG (callexp, 1);
    692      1.1  mrg   return modify_expr (result, value);
    693      1.1  mrg }
    694      1.1  mrg 
    695      1.1  mrg /* If CALLEXP is for an intrinsic , expand and return inlined compiler
    696      1.1  mrg    generated instructions.  Most map directly to GCC builtins, others
    697      1.1  mrg    require a little extra work around them.  */
    698      1.1  mrg 
    699      1.1  mrg tree
    700      1.1  mrg maybe_expand_intrinsic (tree callexp)
    701      1.1  mrg {
    702      1.1  mrg   tree callee = CALL_EXPR_FN (callexp);
    703      1.1  mrg 
    704      1.1  mrg   if (TREE_CODE (callee) == ADDR_EXPR)
    705      1.1  mrg     callee = TREE_OPERAND (callee, 0);
    706      1.1  mrg 
    707      1.1  mrg   if (TREE_CODE (callee) != FUNCTION_DECL)
    708      1.1  mrg     return callexp;
    709      1.1  mrg 
    710      1.1  mrg   /* Don't expand CTFE-only intrinsics outside of semantic processing.  */
    711      1.1  mrg   if (DECL_BUILT_IN_CTFE (callee) && !doing_semantic_analysis_p)
    712      1.1  mrg     return callexp;
    713      1.1  mrg 
    714      1.1  mrg   intrinsic_code intrinsic = DECL_INTRINSIC_CODE (callee);
    715      1.1  mrg   built_in_function code;
    716      1.1  mrg 
    717      1.1  mrg   switch (intrinsic)
    718      1.1  mrg     {
    719      1.1  mrg     case INTRINSIC_NONE:
    720      1.1  mrg       return callexp;
    721      1.1  mrg 
    722      1.1  mrg     case INTRINSIC_BSF:
    723      1.1  mrg       return expand_intrinsic_bsf (callexp);
    724      1.1  mrg 
    725      1.1  mrg     case INTRINSIC_BSR:
    726      1.1  mrg       return expand_intrinsic_bsr (callexp);
    727      1.1  mrg 
    728      1.1  mrg     case INTRINSIC_BT:
    729      1.1  mrg     case INTRINSIC_BTC:
    730      1.1  mrg     case INTRINSIC_BTR:
    731      1.1  mrg     case INTRINSIC_BTS:
    732      1.1  mrg       return expand_intrinsic_bt (intrinsic, callexp);
    733      1.1  mrg 
    734      1.1  mrg     case INTRINSIC_BSWAP:
    735      1.1  mrg       return expand_intrinsic_bswap (callexp);
    736      1.1  mrg 
    737      1.1  mrg     case INTRINSIC_POPCNT:
    738      1.1  mrg       return expand_intrinsic_popcnt (callexp);
    739      1.1  mrg 
    740      1.1  mrg     case INTRINSIC_COS:
    741      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_COSL, 1,
    742      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    743      1.1  mrg 
    744      1.1  mrg     case INTRINSIC_SIN:
    745      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_SINL, 1,
    746      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    747      1.1  mrg 
    748      1.1  mrg     case INTRINSIC_RNDTOL:
    749      1.1  mrg       /* Not sure if llroundl stands as a good replacement for the
    750      1.1  mrg 	 expected behavior of rndtol.  */
    751      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LLROUNDL, 1,
    752      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    753      1.1  mrg 
    754      1.1  mrg     case INTRINSIC_SQRT:
    755      1.1  mrg     case INTRINSIC_SQRTF:
    756      1.1  mrg     case INTRINSIC_SQRTL:
    757      1.1  mrg       return expand_intrinsic_sqrt (intrinsic, callexp);
    758      1.1  mrg 
    759      1.1  mrg     case INTRINSIC_LDEXP:
    760      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LDEXPL, 2,
    761      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    762      1.1  mrg 			      CALL_EXPR_ARG (callexp, 1));
    763      1.1  mrg 
    764      1.1  mrg     case INTRINSIC_FABS:
    765      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FABSL, 1,
    766      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    767      1.1  mrg 
    768      1.1  mrg     case INTRINSIC_RINT:
    769      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_RINTL, 1,
    770      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    771      1.1  mrg 
    772      1.1  mrg     case INTRINSIC_TAN:
    773      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_TANL, 1,
    774      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    775      1.1  mrg 
    776      1.1  mrg     case INTRINSIC_ISNAN:
    777      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ISNAN, 1,
    778      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    779      1.1  mrg 
    780      1.1  mrg     case INTRINSIC_ISINFINITY:
    781      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ISINF, 1,
    782      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    783      1.1  mrg 
    784      1.1  mrg     case INTRINSIC_ISFINITE:
    785      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ISFINITE, 1,
    786      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    787      1.1  mrg 
    788      1.1  mrg     case INTRINSIC_EXP:
    789      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_EXPL, 1,
    790      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    791      1.1  mrg 
    792      1.1  mrg     case INTRINSIC_EXPM1:
    793      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_EXPM1L, 1,
    794      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    795      1.1  mrg 
    796      1.1  mrg     case INTRINSIC_EXP2:
    797      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_EXP2L, 1,
    798      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    799      1.1  mrg 
    800      1.1  mrg     case INTRINSIC_LOG:
    801      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LOGL, 1,
    802      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    803      1.1  mrg 
    804      1.1  mrg     case INTRINSIC_LOG2:
    805      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LOG2L, 1,
    806      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    807      1.1  mrg 
    808      1.1  mrg     case INTRINSIC_LOG10:
    809      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LOG10L, 1,
    810      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    811      1.1  mrg 
    812      1.1  mrg     case INTRINSIC_ROUND:
    813      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ROUNDL, 1,
    814      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    815      1.1  mrg 
    816      1.1  mrg     case INTRINSIC_FLOORF:
    817      1.1  mrg     case INTRINSIC_FLOOR:
    818      1.1  mrg     case INTRINSIC_FLOORL:
    819      1.1  mrg       code = (intrinsic == INTRINSIC_FLOOR) ? BUILT_IN_FLOOR
    820      1.1  mrg 	: (intrinsic == INTRINSIC_FLOORF) ? BUILT_IN_FLOORF
    821      1.1  mrg 	: BUILT_IN_FLOORL;
    822      1.1  mrg       return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0));
    823      1.1  mrg 
    824      1.1  mrg     case INTRINSIC_CEILF:
    825      1.1  mrg     case INTRINSIC_CEIL:
    826      1.1  mrg     case INTRINSIC_CEILL:
    827      1.1  mrg       code = (intrinsic == INTRINSIC_CEIL) ? BUILT_IN_CEIL
    828      1.1  mrg 	: (intrinsic == INTRINSIC_CEILF) ? BUILT_IN_CEILF
    829      1.1  mrg 	: BUILT_IN_CEILL;
    830      1.1  mrg       return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0));
    831      1.1  mrg 
    832      1.1  mrg     case INTRINSIC_TRUNC:
    833      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_TRUNCL, 1,
    834      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    835      1.1  mrg 
    836      1.1  mrg     case INTRINSIC_FMIN:
    837      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FMINL, 2,
    838      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    839      1.1  mrg 			      CALL_EXPR_ARG (callexp, 1));
    840      1.1  mrg 
    841      1.1  mrg     case INTRINSIC_FMAX:
    842      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FMAXL, 2,
    843      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    844      1.1  mrg 			      CALL_EXPR_ARG (callexp, 1));
    845      1.1  mrg 
    846      1.1  mrg     case INTRINSIC_COPYSIGN:
    847      1.1  mrg       return expand_intrinsic_copysign (callexp);
    848      1.1  mrg 
    849      1.1  mrg     case INTRINSIC_POW:
    850      1.1  mrg       return expand_intrinsic_pow (callexp);
    851      1.1  mrg 
    852      1.1  mrg     case INTRINSIC_FMA:
    853      1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FMAL, 3,
    854      1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    855      1.1  mrg 			      CALL_EXPR_ARG (callexp, 1),
    856      1.1  mrg 			      CALL_EXPR_ARG (callexp, 2));
    857      1.1  mrg 
    858  1.1.1.2  mrg     case INTRINSIC_TOPREC:
    859  1.1.1.2  mrg       return expand_intrinsic_toprec (callexp);
    860  1.1.1.2  mrg 
    861      1.1  mrg     case INTRINSIC_VA_ARG:
    862      1.1  mrg     case INTRINSIC_C_VA_ARG:
    863      1.1  mrg       return expand_intrinsic_vaarg (callexp);
    864      1.1  mrg 
    865      1.1  mrg     case INTRINSIC_VASTART:
    866      1.1  mrg       return expand_intrinsic_vastart (callexp);
    867      1.1  mrg 
    868      1.1  mrg     case INTRINSIC_ADDS:
    869      1.1  mrg     case INTRINSIC_SUBS:
    870      1.1  mrg     case INTRINSIC_MULS:
    871      1.1  mrg     case INTRINSIC_NEGS:
    872      1.1  mrg       return expand_intrinsic_checkedint (intrinsic, callexp);
    873      1.1  mrg 
    874      1.1  mrg     case INTRINSIC_VLOAD:
    875      1.1  mrg       return expand_volatile_load (callexp);
    876      1.1  mrg 
    877      1.1  mrg     case INTRINSIC_VSTORE:
    878      1.1  mrg       return expand_volatile_store (callexp);
    879      1.1  mrg 
    880      1.1  mrg     default:
    881      1.1  mrg       gcc_unreachable ();
    882      1.1  mrg     }
    883      1.1  mrg }
    884