Home | History | Annotate | Line # | Download | only in d
intrinsics.cc revision 1.1
      1  1.1  mrg /* intrinsics.cc -- D language compiler intrinsics.
      2  1.1  mrg    Copyright (C) 2006-2019 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  mrg 	    {
    138  1.1  mrg 	      DECL_BUILT_IN_CLASS (decl->csym) = BUILT_IN_FRONTEND;
    139  1.1  mrg 	      DECL_FUNCTION_CODE (decl->csym) = (built_in_function) code;
    140  1.1  mrg 	    }
    141  1.1  mrg 
    142  1.1  mrg 	  /* Infer whether the intrinsic can be used for CTFE, let the
    143  1.1  mrg 	     front-end know that it can be evaluated at compile-time.  */
    144  1.1  mrg 	  switch (code)
    145  1.1  mrg 	    {
    146  1.1  mrg 	    case INTRINSIC_VA_ARG:
    147  1.1  mrg 	    case INTRINSIC_C_VA_ARG:
    148  1.1  mrg 	    case INTRINSIC_VASTART:
    149  1.1  mrg 	    case INTRINSIC_ADDS:
    150  1.1  mrg 	    case INTRINSIC_SUBS:
    151  1.1  mrg 	    case INTRINSIC_MULS:
    152  1.1  mrg 	    case INTRINSIC_NEGS:
    153  1.1  mrg 	    case INTRINSIC_VLOAD:
    154  1.1  mrg 	    case INTRINSIC_VSTORE:
    155  1.1  mrg 	      break;
    156  1.1  mrg 
    157  1.1  mrg 	    case INTRINSIC_POW:
    158  1.1  mrg 	    {
    159  1.1  mrg 	      /* Check that this overload of pow() is has an equivalent
    160  1.1  mrg 		 built-in function.  It could be `int pow(int, int)'.  */
    161  1.1  mrg 	      tree rettype = TREE_TYPE (TREE_TYPE (decl->csym));
    162  1.1  mrg 	      if (mathfn_built_in (rettype, BUILT_IN_POW) != NULL_TREE)
    163  1.1  mrg 		decl->builtin = BUILTINyes;
    164  1.1  mrg 	      break;
    165  1.1  mrg 	    }
    166  1.1  mrg 
    167  1.1  mrg 	    default:
    168  1.1  mrg 	      decl->builtin = BUILTINyes;
    169  1.1  mrg 	      break;
    170  1.1  mrg 	    }
    171  1.1  mrg 
    172  1.1  mrg 	  /* The intrinsic was marked as CTFE-only.  */
    173  1.1  mrg 	  if (intrinsic_decls[i].ctfeonly)
    174  1.1  mrg 	    DECL_BUILT_IN_CTFE (decl->csym) = 1;
    175  1.1  mrg 
    176  1.1  mrg 	  DECL_INTRINSIC_CODE (decl->csym) = code;
    177  1.1  mrg 	  break;
    178  1.1  mrg 	}
    179  1.1  mrg     }
    180  1.1  mrg }
    181  1.1  mrg 
    182  1.1  mrg /* Construct a function call to the built-in function CODE, N is the number of
    183  1.1  mrg    arguments, and the `...' parameters are the argument expressions.
    184  1.1  mrg    The original call expression is held in CALLEXP.  */
    185  1.1  mrg 
    186  1.1  mrg static tree
    187  1.1  mrg call_builtin_fn (tree callexp, built_in_function code, int n, ...)
    188  1.1  mrg {
    189  1.1  mrg   tree *argarray = XALLOCAVEC (tree, n);
    190  1.1  mrg   va_list ap;
    191  1.1  mrg 
    192  1.1  mrg   va_start (ap, n);
    193  1.1  mrg   for (int i = 0; i < n; i++)
    194  1.1  mrg     argarray[i] = va_arg (ap, tree);
    195  1.1  mrg   va_end (ap);
    196  1.1  mrg 
    197  1.1  mrg   tree exp = build_call_expr_loc_array (EXPR_LOCATION (callexp),
    198  1.1  mrg 					builtin_decl_explicit (code),
    199  1.1  mrg 					n, argarray);
    200  1.1  mrg   return convert (TREE_TYPE (callexp), fold (exp));
    201  1.1  mrg }
    202  1.1  mrg 
    203  1.1  mrg /* Expand a front-end instrinsic call to bsf().  This takes one argument,
    204  1.1  mrg    the signature to which can be either:
    205  1.1  mrg 
    206  1.1  mrg 	int bsf (uint arg);
    207  1.1  mrg 	int bsf (ulong arg);
    208  1.1  mrg 
    209  1.1  mrg    This scans all bits in the given argument starting with the first,
    210  1.1  mrg    returning the bit number of the first bit set.  The original call
    211  1.1  mrg    expression is held in CALLEXP.  */
    212  1.1  mrg 
    213  1.1  mrg static tree
    214  1.1  mrg expand_intrinsic_bsf (tree callexp)
    215  1.1  mrg {
    216  1.1  mrg   /* The bsr() intrinsic gets turned into __builtin_ctz(arg).
    217  1.1  mrg      The return value is supposed to be undefined if arg is zero.  */
    218  1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    219  1.1  mrg   int argsize = TYPE_PRECISION (TREE_TYPE (arg));
    220  1.1  mrg 
    221  1.1  mrg   /* Which variant of __builtin_ctz* should we call?  */
    222  1.1  mrg   built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CTZ
    223  1.1  mrg     : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CTZL
    224  1.1  mrg     : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CTZLL
    225  1.1  mrg     : END_BUILTINS;
    226  1.1  mrg 
    227  1.1  mrg   gcc_assert (code != END_BUILTINS);
    228  1.1  mrg 
    229  1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    230  1.1  mrg }
    231  1.1  mrg 
    232  1.1  mrg /* Expand a front-end instrinsic call to bsr().  This takes one argument,
    233  1.1  mrg    the signature to which can be either:
    234  1.1  mrg 
    235  1.1  mrg 	int bsr (uint arg);
    236  1.1  mrg 	int bsr (ulong arg);
    237  1.1  mrg 
    238  1.1  mrg    This scans all bits in the given argument from the most significant bit
    239  1.1  mrg    to the least significant, returning the bit number of the first bit set.
    240  1.1  mrg    The original call expression is held in CALLEXP.  */
    241  1.1  mrg 
    242  1.1  mrg static tree
    243  1.1  mrg expand_intrinsic_bsr (tree callexp)
    244  1.1  mrg {
    245  1.1  mrg   /* The bsr() intrinsic gets turned into (size - 1) - __builtin_clz(arg).
    246  1.1  mrg      The return value is supposed to be undefined if arg is zero.  */
    247  1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    248  1.1  mrg   tree type = TREE_TYPE (arg);
    249  1.1  mrg   int argsize = TYPE_PRECISION (type);
    250  1.1  mrg 
    251  1.1  mrg   /* Which variant of __builtin_clz* should we call?  */
    252  1.1  mrg   built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CLZ
    253  1.1  mrg     : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CLZL
    254  1.1  mrg     : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CLZLL
    255  1.1  mrg     : END_BUILTINS;
    256  1.1  mrg 
    257  1.1  mrg   gcc_assert (code != END_BUILTINS);
    258  1.1  mrg 
    259  1.1  mrg   tree result = call_builtin_fn (callexp, code, 1, arg);
    260  1.1  mrg 
    261  1.1  mrg   /* Handle int -> long conversions.  */
    262  1.1  mrg   if (TREE_TYPE (result) != type)
    263  1.1  mrg     result = fold_convert (type, result);
    264  1.1  mrg 
    265  1.1  mrg   result = fold_build2 (MINUS_EXPR, type,
    266  1.1  mrg 			build_integer_cst (argsize - 1, type), result);
    267  1.1  mrg   return fold_convert (TREE_TYPE (callexp), result);
    268  1.1  mrg }
    269  1.1  mrg 
    270  1.1  mrg /* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
    271  1.1  mrg    bt(), btc(), btr(), or bts().  These intrinsics expect to take two arguments,
    272  1.1  mrg    the signature to which is:
    273  1.1  mrg 
    274  1.1  mrg 	int bt (size_t* ptr, size_t bitnum);
    275  1.1  mrg 
    276  1.1  mrg    All intrinsics test if a bit is set and return the result of that condition.
    277  1.1  mrg    Variants of `bt' will then update that bit. `btc' compliments the bit, `bts'
    278  1.1  mrg    sets the bit, and `btr' resets the bit.  The original call expression is
    279  1.1  mrg    held in CALLEXP.  */
    280  1.1  mrg 
    281  1.1  mrg static tree
    282  1.1  mrg expand_intrinsic_bt (intrinsic_code intrinsic, tree callexp)
    283  1.1  mrg {
    284  1.1  mrg   tree ptr = CALL_EXPR_ARG (callexp, 0);
    285  1.1  mrg   tree bitnum = CALL_EXPR_ARG (callexp, 1);
    286  1.1  mrg   tree type = TREE_TYPE (TREE_TYPE (ptr));
    287  1.1  mrg 
    288  1.1  mrg   /* size_t bitsize = sizeof(*ptr) * BITS_PER_UNIT;  */
    289  1.1  mrg   tree bitsize = fold_convert (type, TYPE_SIZE (type));
    290  1.1  mrg 
    291  1.1  mrg   /* ptr[bitnum / bitsize]  */
    292  1.1  mrg   ptr = build_array_index (ptr, fold_build2 (TRUNC_DIV_EXPR, type,
    293  1.1  mrg 					     bitnum, bitsize));
    294  1.1  mrg   ptr = indirect_ref (type, ptr);
    295  1.1  mrg 
    296  1.1  mrg   /* mask = 1 << (bitnum % bitsize);  */
    297  1.1  mrg   bitnum = fold_build2 (TRUNC_MOD_EXPR, type, bitnum, bitsize);
    298  1.1  mrg   bitnum = fold_build2 (LSHIFT_EXPR, type, size_one_node, bitnum);
    299  1.1  mrg 
    300  1.1  mrg   /* cond = ptr[bitnum / size] & mask;  */
    301  1.1  mrg   tree cond = fold_build2 (BIT_AND_EXPR, type, ptr, bitnum);
    302  1.1  mrg 
    303  1.1  mrg   /* cond ? -1 : 0;  */
    304  1.1  mrg   cond = build_condition (TREE_TYPE (callexp), d_truthvalue_conversion (cond),
    305  1.1  mrg 			 integer_minus_one_node, integer_zero_node);
    306  1.1  mrg 
    307  1.1  mrg   /* Update the bit as needed, only testing the bit for bt().  */
    308  1.1  mrg   if (intrinsic == INTRINSIC_BT)
    309  1.1  mrg     return cond;
    310  1.1  mrg 
    311  1.1  mrg   tree_code code = (intrinsic == INTRINSIC_BTC) ? BIT_XOR_EXPR
    312  1.1  mrg     : (intrinsic == INTRINSIC_BTR) ? BIT_AND_EXPR
    313  1.1  mrg     : (intrinsic == INTRINSIC_BTS) ? BIT_IOR_EXPR
    314  1.1  mrg     : ERROR_MARK;
    315  1.1  mrg   gcc_assert (code != ERROR_MARK);
    316  1.1  mrg 
    317  1.1  mrg   /* ptr[bitnum / size] op= mask;  */
    318  1.1  mrg   if (intrinsic == INTRINSIC_BTR)
    319  1.1  mrg     bitnum = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (bitnum), bitnum);
    320  1.1  mrg 
    321  1.1  mrg   ptr = modify_expr (ptr, fold_build2 (code, TREE_TYPE (ptr), ptr, bitnum));
    322  1.1  mrg 
    323  1.1  mrg   /* Store the condition result in a temporary, and return expressions in
    324  1.1  mrg      correct order of evaluation.  */
    325  1.1  mrg   tree tmp = build_local_temp (TREE_TYPE (callexp));
    326  1.1  mrg   cond = modify_expr (tmp, cond);
    327  1.1  mrg 
    328  1.1  mrg   return compound_expr (cond, compound_expr (ptr, tmp));
    329  1.1  mrg }
    330  1.1  mrg 
    331  1.1  mrg /* Expand a front-end intrinsic call to bswap().  This takes one argument, the
    332  1.1  mrg    signature to which can be either:
    333  1.1  mrg 
    334  1.1  mrg 	int bswap (uint arg);
    335  1.1  mrg 	int bswap (ulong arg);
    336  1.1  mrg 
    337  1.1  mrg    This swaps all bytes in an N byte type end-to-end.  The original call
    338  1.1  mrg    expression is held in CALLEXP.  */
    339  1.1  mrg 
    340  1.1  mrg static tree
    341  1.1  mrg expand_intrinsic_bswap (tree callexp)
    342  1.1  mrg {
    343  1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    344  1.1  mrg   int argsize = TYPE_PRECISION (TREE_TYPE (arg));
    345  1.1  mrg 
    346  1.1  mrg   /* Which variant of __builtin_bswap* should we call?  */
    347  1.1  mrg   built_in_function code = (argsize == 32) ? BUILT_IN_BSWAP32
    348  1.1  mrg     : (argsize == 64) ? BUILT_IN_BSWAP64
    349  1.1  mrg     : END_BUILTINS;
    350  1.1  mrg 
    351  1.1  mrg   gcc_assert (code != END_BUILTINS);
    352  1.1  mrg 
    353  1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    354  1.1  mrg }
    355  1.1  mrg 
    356  1.1  mrg /* Expand a front-end intrinsic call to popcnt().  This takes one argument, the
    357  1.1  mrg    signature to which can be either:
    358  1.1  mrg 
    359  1.1  mrg 	int popcnt (uint arg);
    360  1.1  mrg 	int popcnt (ulong arg);
    361  1.1  mrg 
    362  1.1  mrg    Calculates the number of set bits in an integer.  The original call
    363  1.1  mrg    expression is held in CALLEXP.  */
    364  1.1  mrg 
    365  1.1  mrg static tree
    366  1.1  mrg expand_intrinsic_popcnt (tree callexp)
    367  1.1  mrg {
    368  1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    369  1.1  mrg   int argsize = TYPE_PRECISION (TREE_TYPE (arg));
    370  1.1  mrg 
    371  1.1  mrg   /* Which variant of __builtin_popcount* should we call?  */
    372  1.1  mrg   built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_POPCOUNT
    373  1.1  mrg     : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTL
    374  1.1  mrg     : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTLL
    375  1.1  mrg     : END_BUILTINS;
    376  1.1  mrg 
    377  1.1  mrg   gcc_assert (code != END_BUILTINS);
    378  1.1  mrg 
    379  1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    380  1.1  mrg }
    381  1.1  mrg 
    382  1.1  mrg /* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
    383  1.1  mrg    sqrt(), sqrtf(), sqrtl().  These intrinsics expect to take one argument,
    384  1.1  mrg    the signature to which can be either:
    385  1.1  mrg 
    386  1.1  mrg 	float sqrt (float arg);
    387  1.1  mrg 	double sqrt (double arg);
    388  1.1  mrg 	real sqrt (real arg);
    389  1.1  mrg 
    390  1.1  mrg    This computes the square root of the given argument.  The original call
    391  1.1  mrg    expression is held in CALLEXP.  */
    392  1.1  mrg 
    393  1.1  mrg static tree
    394  1.1  mrg expand_intrinsic_sqrt (intrinsic_code intrinsic, tree callexp)
    395  1.1  mrg {
    396  1.1  mrg   tree arg = CALL_EXPR_ARG (callexp, 0);
    397  1.1  mrg 
    398  1.1  mrg   /* Which variant of __builtin_sqrt* should we call?  */
    399  1.1  mrg   built_in_function code = (intrinsic == INTRINSIC_SQRT) ? BUILT_IN_SQRT
    400  1.1  mrg     : (intrinsic == INTRINSIC_SQRTF) ? BUILT_IN_SQRTF
    401  1.1  mrg     : (intrinsic == INTRINSIC_SQRTL) ? BUILT_IN_SQRTL
    402  1.1  mrg     : END_BUILTINS;
    403  1.1  mrg 
    404  1.1  mrg   gcc_assert (code != END_BUILTINS);
    405  1.1  mrg   return call_builtin_fn (callexp, code, 1, arg);
    406  1.1  mrg }
    407  1.1  mrg 
    408  1.1  mrg /* Expand a front-end intrinsic call to copysign().  This takes two arguments,
    409  1.1  mrg    the signature to which can be either:
    410  1.1  mrg 
    411  1.1  mrg 	float copysign (T to, float from);
    412  1.1  mrg 	double copysign (T to, double from);
    413  1.1  mrg 	real copysign (T to, real from);
    414  1.1  mrg 
    415  1.1  mrg    This computes a value composed of TO with the sign bit of FROM.  The original
    416  1.1  mrg    call expression is held in CALLEXP.  */
    417  1.1  mrg 
    418  1.1  mrg static tree
    419  1.1  mrg expand_intrinsic_copysign (tree callexp)
    420  1.1  mrg {
    421  1.1  mrg   tree to = CALL_EXPR_ARG (callexp, 0);
    422  1.1  mrg   tree from = CALL_EXPR_ARG (callexp, 1);
    423  1.1  mrg   tree type = TREE_TYPE (to);
    424  1.1  mrg 
    425  1.1  mrg   /* Convert parameters to the same type.  Prefer the first parameter unless it
    426  1.1  mrg      is an integral type.  */
    427  1.1  mrg   if (INTEGRAL_TYPE_P (type))
    428  1.1  mrg     {
    429  1.1  mrg       to = fold_convert (TREE_TYPE (from), to);
    430  1.1  mrg       type = TREE_TYPE (to);
    431  1.1  mrg     }
    432  1.1  mrg   else
    433  1.1  mrg     from = fold_convert (type, from);
    434  1.1  mrg 
    435  1.1  mrg   /* Which variant of __builtin_copysign* should we call?  */
    436  1.1  mrg   tree builtin = mathfn_built_in (type, BUILT_IN_COPYSIGN);
    437  1.1  mrg   gcc_assert (builtin != NULL_TREE);
    438  1.1  mrg 
    439  1.1  mrg   return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2,
    440  1.1  mrg 			  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  mrg /* Expand a front-end intrinsic call to va_arg().  This takes either one or two
    474  1.1  mrg    arguments, the signature to which can be either:
    475  1.1  mrg 
    476  1.1  mrg 	T va_arg(T) (ref va_list ap);
    477  1.1  mrg 	void va_arg(T) (va_list ap, ref T parmn);
    478  1.1  mrg 
    479  1.1  mrg    This retrieves the next variadic parameter that is type T from the given
    480  1.1  mrg    va_list.  If also given, store the value into parmn, otherwise return it.
    481  1.1  mrg    The original call expression is held in CALLEXP.  */
    482  1.1  mrg 
    483  1.1  mrg static tree
    484  1.1  mrg expand_intrinsic_vaarg (tree callexp)
    485  1.1  mrg {
    486  1.1  mrg   tree ap = CALL_EXPR_ARG (callexp, 0);
    487  1.1  mrg   tree parmn = NULL_TREE;
    488  1.1  mrg   tree type;
    489  1.1  mrg 
    490  1.1  mrg   STRIP_NOPS (ap);
    491  1.1  mrg 
    492  1.1  mrg   if (call_expr_nargs (callexp) == 1)
    493  1.1  mrg     type = TREE_TYPE (callexp);
    494  1.1  mrg   else
    495  1.1  mrg     {
    496  1.1  mrg       parmn = CALL_EXPR_ARG (callexp, 1);
    497  1.1  mrg       STRIP_NOPS (parmn);
    498  1.1  mrg       gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
    499  1.1  mrg       parmn = TREE_OPERAND (parmn, 0);
    500  1.1  mrg       type = TREE_TYPE (parmn);
    501  1.1  mrg     }
    502  1.1  mrg 
    503  1.1  mrg   /* (T) VA_ARG_EXP<ap>;  */
    504  1.1  mrg   tree exp = build1 (VA_ARG_EXPR, type, ap);
    505  1.1  mrg 
    506  1.1  mrg   /* parmn = (T) VA_ARG_EXP<ap>;  */
    507  1.1  mrg   if (parmn != NULL_TREE)
    508  1.1  mrg     exp = modify_expr (parmn, exp);
    509  1.1  mrg 
    510  1.1  mrg   return exp;
    511  1.1  mrg }
    512  1.1  mrg 
    513  1.1  mrg /* Expand a front-end intrinsic call to va_start(), which takes two arguments,
    514  1.1  mrg    the signature to which is:
    515  1.1  mrg 
    516  1.1  mrg 	void va_start(T) (out va_list ap, ref T parmn);
    517  1.1  mrg 
    518  1.1  mrg    This initializes the va_list type, where parmn should be the last named
    519  1.1  mrg    parameter.  The original call expression is held in CALLEXP.  */
    520  1.1  mrg 
    521  1.1  mrg static tree
    522  1.1  mrg expand_intrinsic_vastart (tree callexp)
    523  1.1  mrg {
    524  1.1  mrg   tree ap = CALL_EXPR_ARG (callexp, 0);
    525  1.1  mrg   tree parmn = CALL_EXPR_ARG (callexp, 1);
    526  1.1  mrg 
    527  1.1  mrg   STRIP_NOPS (ap);
    528  1.1  mrg   STRIP_NOPS (parmn);
    529  1.1  mrg 
    530  1.1  mrg   /* The va_list argument should already have its address taken.  The second
    531  1.1  mrg      argument, however, is inout and that needs to be fixed to prevent a
    532  1.1  mrg      warning.  Could be casting, so need to check type too?  */
    533  1.1  mrg   gcc_assert (TREE_CODE (ap) == ADDR_EXPR && TREE_CODE (parmn) == ADDR_EXPR);
    534  1.1  mrg 
    535  1.1  mrg   /* Assuming nobody tries to change the return type.  */
    536  1.1  mrg   parmn = TREE_OPERAND (parmn, 0);
    537  1.1  mrg 
    538  1.1  mrg   return call_builtin_fn (callexp, BUILT_IN_VA_START, 2, ap, parmn);
    539  1.1  mrg }
    540  1.1  mrg 
    541  1.1  mrg /* Expand a front-end instrinsic call to INTRINSIC, which is either a call to
    542  1.1  mrg    adds(), addu(), subs(), subu(), negs(), muls(), or mulu().  These intrinsics
    543  1.1  mrg    expect to take two or three arguments, the signature to which can be either:
    544  1.1  mrg 
    545  1.1  mrg 	int adds (int x, int y, ref bool overflow);
    546  1.1  mrg 	long adds (long x, long y, ref bool overflow);
    547  1.1  mrg 	int negs (int x, ref bool overflow);
    548  1.1  mrg 	long negs (long x, ref bool overflow);
    549  1.1  mrg 
    550  1.1  mrg    This performs an operation on two signed or unsigned integers, checking for
    551  1.1  mrg    overflow.  The overflow is sticky, meaning that a sequence of operations
    552  1.1  mrg    can be done and overflow need only be checked at the end.  The original call
    553  1.1  mrg    expression is held in CALLEXP.  */
    554  1.1  mrg 
    555  1.1  mrg static tree
    556  1.1  mrg expand_intrinsic_checkedint (intrinsic_code intrinsic, tree callexp)
    557  1.1  mrg {
    558  1.1  mrg   tree type = TREE_TYPE (callexp);
    559  1.1  mrg   tree x;
    560  1.1  mrg   tree y;
    561  1.1  mrg   tree overflow;
    562  1.1  mrg 
    563  1.1  mrg   /* The negs() intrinsic gets turned into SUB_OVERFLOW (0, y).  */
    564  1.1  mrg   if (intrinsic == INTRINSIC_NEGS)
    565  1.1  mrg     {
    566  1.1  mrg       x = fold_convert (type, integer_zero_node);
    567  1.1  mrg       y = CALL_EXPR_ARG (callexp, 0);
    568  1.1  mrg       overflow = CALL_EXPR_ARG (callexp, 1);
    569  1.1  mrg     }
    570  1.1  mrg   else
    571  1.1  mrg     {
    572  1.1  mrg       x = CALL_EXPR_ARG (callexp, 0);
    573  1.1  mrg       y = CALL_EXPR_ARG (callexp, 1);
    574  1.1  mrg       overflow = CALL_EXPR_ARG (callexp, 2);
    575  1.1  mrg     }
    576  1.1  mrg 
    577  1.1  mrg   /* Which variant of *_OVERFLOW should we generate?  */
    578  1.1  mrg   internal_fn icode = (intrinsic == INTRINSIC_ADDS) ? IFN_ADD_OVERFLOW
    579  1.1  mrg     : (intrinsic == INTRINSIC_SUBS) ? IFN_SUB_OVERFLOW
    580  1.1  mrg     : (intrinsic == INTRINSIC_MULS) ? IFN_MUL_OVERFLOW
    581  1.1  mrg     : (intrinsic == INTRINSIC_NEGS) ? IFN_SUB_OVERFLOW
    582  1.1  mrg     : IFN_LAST;
    583  1.1  mrg   gcc_assert (icode != IFN_LAST);
    584  1.1  mrg 
    585  1.1  mrg   tree result
    586  1.1  mrg     = build_call_expr_internal_loc (EXPR_LOCATION (callexp), icode,
    587  1.1  mrg 				    build_complex_type (type), 2, x, y);
    588  1.1  mrg 
    589  1.1  mrg   STRIP_NOPS (overflow);
    590  1.1  mrg   overflow = build_deref (overflow);
    591  1.1  mrg 
    592  1.1  mrg   /* Assign returned result to overflow parameter, however if overflow is
    593  1.1  mrg      already true, maintain its value.  */
    594  1.1  mrg   type = TREE_TYPE (overflow);
    595  1.1  mrg   result = save_expr (result);
    596  1.1  mrg 
    597  1.1  mrg   tree exp = fold_build2 (BIT_IOR_EXPR, type, overflow,
    598  1.1  mrg 			  fold_convert (type, imaginary_part (result)));
    599  1.1  mrg   exp = modify_expr (overflow, exp);
    600  1.1  mrg 
    601  1.1  mrg   /* Return the value of result.  */
    602  1.1  mrg   return compound_expr (exp, real_part (result));
    603  1.1  mrg }
    604  1.1  mrg 
    605  1.1  mrg /* Expand a front-end instrinsic call to volatileLoad().  This takes one
    606  1.1  mrg    argument, the signature to which can be either:
    607  1.1  mrg 
    608  1.1  mrg 	ubyte volatileLoad (ubyte* ptr);
    609  1.1  mrg 	ushort volatileLoad (ushort* ptr);
    610  1.1  mrg 	uint volatileLoad (uint* ptr);
    611  1.1  mrg 	ulong volatileLoad (ulong* ptr);
    612  1.1  mrg 
    613  1.1  mrg    This reads a value from the memory location indicated by ptr.  Calls to
    614  1.1  mrg    them are be guaranteed to not be removed (such as during DCE) or reordered
    615  1.1  mrg    in the same thread.  The original call expression is held in CALLEXP.  */
    616  1.1  mrg 
    617  1.1  mrg static tree
    618  1.1  mrg expand_volatile_load (tree callexp)
    619  1.1  mrg {
    620  1.1  mrg   tree ptr = CALL_EXPR_ARG (callexp, 0);
    621  1.1  mrg   tree ptrtype = TREE_TYPE (ptr);
    622  1.1  mrg   gcc_assert (POINTER_TYPE_P (ptrtype));
    623  1.1  mrg 
    624  1.1  mrg   /* (T) *(volatile T *) ptr;  */
    625  1.1  mrg   tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
    626  1.1  mrg   tree result = indirect_ref (type, ptr);
    627  1.1  mrg   TREE_THIS_VOLATILE (result) = 1;
    628  1.1  mrg 
    629  1.1  mrg   return result;
    630  1.1  mrg }
    631  1.1  mrg 
    632  1.1  mrg /* Expand a front-end instrinsic call to volatileStore().  This takes two
    633  1.1  mrg    arguments, the signature to which can be either:
    634  1.1  mrg 
    635  1.1  mrg 	void volatileStore (ubyte* ptr, ubyte value);
    636  1.1  mrg 	void volatileStore (ushort* ptr, ushort value);
    637  1.1  mrg 	void volatileStore (uint* ptr, uint value);
    638  1.1  mrg 	void volatileStore (ulong* ptr, ulong value);
    639  1.1  mrg 
    640  1.1  mrg    This writes a value to the memory location indicated by ptr.  Calls to
    641  1.1  mrg    them are be guaranteed to not be removed (such as during DCE) or reordered
    642  1.1  mrg    in the same thread.  The original call expression is held in CALLEXP.  */
    643  1.1  mrg 
    644  1.1  mrg static tree
    645  1.1  mrg expand_volatile_store (tree callexp)
    646  1.1  mrg {
    647  1.1  mrg   tree ptr = CALL_EXPR_ARG (callexp, 0);
    648  1.1  mrg   tree ptrtype = TREE_TYPE (ptr);
    649  1.1  mrg   gcc_assert (POINTER_TYPE_P (ptrtype));
    650  1.1  mrg 
    651  1.1  mrg   /* (T) *(volatile T *) ptr;  */
    652  1.1  mrg   tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
    653  1.1  mrg   tree result = indirect_ref (type, ptr);
    654  1.1  mrg   TREE_THIS_VOLATILE (result) = 1;
    655  1.1  mrg 
    656  1.1  mrg   /* (*(volatile T *) ptr) = value;  */
    657  1.1  mrg   tree value = CALL_EXPR_ARG (callexp, 1);
    658  1.1  mrg   return modify_expr (result, value);
    659  1.1  mrg }
    660  1.1  mrg 
    661  1.1  mrg /* If CALLEXP is for an intrinsic , expand and return inlined compiler
    662  1.1  mrg    generated instructions.  Most map directly to GCC builtins, others
    663  1.1  mrg    require a little extra work around them.  */
    664  1.1  mrg 
    665  1.1  mrg tree
    666  1.1  mrg maybe_expand_intrinsic (tree callexp)
    667  1.1  mrg {
    668  1.1  mrg   tree callee = CALL_EXPR_FN (callexp);
    669  1.1  mrg 
    670  1.1  mrg   if (TREE_CODE (callee) == ADDR_EXPR)
    671  1.1  mrg     callee = TREE_OPERAND (callee, 0);
    672  1.1  mrg 
    673  1.1  mrg   if (TREE_CODE (callee) != FUNCTION_DECL)
    674  1.1  mrg     return callexp;
    675  1.1  mrg 
    676  1.1  mrg   /* Don't expand CTFE-only intrinsics outside of semantic processing.  */
    677  1.1  mrg   if (DECL_BUILT_IN_CTFE (callee) && !doing_semantic_analysis_p)
    678  1.1  mrg     return callexp;
    679  1.1  mrg 
    680  1.1  mrg   intrinsic_code intrinsic = DECL_INTRINSIC_CODE (callee);
    681  1.1  mrg   built_in_function code;
    682  1.1  mrg 
    683  1.1  mrg   switch (intrinsic)
    684  1.1  mrg     {
    685  1.1  mrg     case INTRINSIC_NONE:
    686  1.1  mrg       return callexp;
    687  1.1  mrg 
    688  1.1  mrg     case INTRINSIC_BSF:
    689  1.1  mrg       return expand_intrinsic_bsf (callexp);
    690  1.1  mrg 
    691  1.1  mrg     case INTRINSIC_BSR:
    692  1.1  mrg       return expand_intrinsic_bsr (callexp);
    693  1.1  mrg 
    694  1.1  mrg     case INTRINSIC_BT:
    695  1.1  mrg     case INTRINSIC_BTC:
    696  1.1  mrg     case INTRINSIC_BTR:
    697  1.1  mrg     case INTRINSIC_BTS:
    698  1.1  mrg       return expand_intrinsic_bt (intrinsic, callexp);
    699  1.1  mrg 
    700  1.1  mrg     case INTRINSIC_BSWAP:
    701  1.1  mrg       return expand_intrinsic_bswap (callexp);
    702  1.1  mrg 
    703  1.1  mrg     case INTRINSIC_POPCNT:
    704  1.1  mrg       return expand_intrinsic_popcnt (callexp);
    705  1.1  mrg 
    706  1.1  mrg     case INTRINSIC_COS:
    707  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_COSL, 1,
    708  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    709  1.1  mrg 
    710  1.1  mrg     case INTRINSIC_SIN:
    711  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_SINL, 1,
    712  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    713  1.1  mrg 
    714  1.1  mrg     case INTRINSIC_RNDTOL:
    715  1.1  mrg       /* Not sure if llroundl stands as a good replacement for the
    716  1.1  mrg 	 expected behavior of rndtol.  */
    717  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LLROUNDL, 1,
    718  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    719  1.1  mrg 
    720  1.1  mrg     case INTRINSIC_SQRT:
    721  1.1  mrg     case INTRINSIC_SQRTF:
    722  1.1  mrg     case INTRINSIC_SQRTL:
    723  1.1  mrg       return expand_intrinsic_sqrt (intrinsic, callexp);
    724  1.1  mrg 
    725  1.1  mrg     case INTRINSIC_LDEXP:
    726  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LDEXPL, 2,
    727  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    728  1.1  mrg 			      CALL_EXPR_ARG (callexp, 1));
    729  1.1  mrg 
    730  1.1  mrg     case INTRINSIC_FABS:
    731  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FABSL, 1,
    732  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    733  1.1  mrg 
    734  1.1  mrg     case INTRINSIC_RINT:
    735  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_RINTL, 1,
    736  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    737  1.1  mrg 
    738  1.1  mrg     case INTRINSIC_TAN:
    739  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_TANL, 1,
    740  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    741  1.1  mrg 
    742  1.1  mrg     case INTRINSIC_ISNAN:
    743  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ISNAN, 1,
    744  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    745  1.1  mrg 
    746  1.1  mrg     case INTRINSIC_ISINFINITY:
    747  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ISINF, 1,
    748  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    749  1.1  mrg 
    750  1.1  mrg     case INTRINSIC_ISFINITE:
    751  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ISFINITE, 1,
    752  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    753  1.1  mrg 
    754  1.1  mrg     case INTRINSIC_EXP:
    755  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_EXPL, 1,
    756  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    757  1.1  mrg 
    758  1.1  mrg     case INTRINSIC_EXPM1:
    759  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_EXPM1L, 1,
    760  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    761  1.1  mrg 
    762  1.1  mrg     case INTRINSIC_EXP2:
    763  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_EXP2L, 1,
    764  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    765  1.1  mrg 
    766  1.1  mrg     case INTRINSIC_LOG:
    767  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LOGL, 1,
    768  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    769  1.1  mrg 
    770  1.1  mrg     case INTRINSIC_LOG2:
    771  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LOG2L, 1,
    772  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    773  1.1  mrg 
    774  1.1  mrg     case INTRINSIC_LOG10:
    775  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_LOG10L, 1,
    776  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    777  1.1  mrg 
    778  1.1  mrg     case INTRINSIC_ROUND:
    779  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_ROUNDL, 1,
    780  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    781  1.1  mrg 
    782  1.1  mrg     case INTRINSIC_FLOORF:
    783  1.1  mrg     case INTRINSIC_FLOOR:
    784  1.1  mrg     case INTRINSIC_FLOORL:
    785  1.1  mrg       code = (intrinsic == INTRINSIC_FLOOR) ? BUILT_IN_FLOOR
    786  1.1  mrg 	: (intrinsic == INTRINSIC_FLOORF) ? BUILT_IN_FLOORF
    787  1.1  mrg 	: BUILT_IN_FLOORL;
    788  1.1  mrg       return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0));
    789  1.1  mrg 
    790  1.1  mrg     case INTRINSIC_CEILF:
    791  1.1  mrg     case INTRINSIC_CEIL:
    792  1.1  mrg     case INTRINSIC_CEILL:
    793  1.1  mrg       code = (intrinsic == INTRINSIC_CEIL) ? BUILT_IN_CEIL
    794  1.1  mrg 	: (intrinsic == INTRINSIC_CEILF) ? BUILT_IN_CEILF
    795  1.1  mrg 	: BUILT_IN_CEILL;
    796  1.1  mrg       return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0));
    797  1.1  mrg 
    798  1.1  mrg     case INTRINSIC_TRUNC:
    799  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_TRUNCL, 1,
    800  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0));
    801  1.1  mrg 
    802  1.1  mrg     case INTRINSIC_FMIN:
    803  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FMINL, 2,
    804  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    805  1.1  mrg 			      CALL_EXPR_ARG (callexp, 1));
    806  1.1  mrg 
    807  1.1  mrg     case INTRINSIC_FMAX:
    808  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FMAXL, 2,
    809  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    810  1.1  mrg 			      CALL_EXPR_ARG (callexp, 1));
    811  1.1  mrg 
    812  1.1  mrg     case INTRINSIC_COPYSIGN:
    813  1.1  mrg       return expand_intrinsic_copysign (callexp);
    814  1.1  mrg 
    815  1.1  mrg     case INTRINSIC_POW:
    816  1.1  mrg       return expand_intrinsic_pow (callexp);
    817  1.1  mrg 
    818  1.1  mrg     case INTRINSIC_FMA:
    819  1.1  mrg       return call_builtin_fn (callexp, BUILT_IN_FMAL, 3,
    820  1.1  mrg 			      CALL_EXPR_ARG (callexp, 0),
    821  1.1  mrg 			      CALL_EXPR_ARG (callexp, 1),
    822  1.1  mrg 			      CALL_EXPR_ARG (callexp, 2));
    823  1.1  mrg 
    824  1.1  mrg     case INTRINSIC_VA_ARG:
    825  1.1  mrg     case INTRINSIC_C_VA_ARG:
    826  1.1  mrg       return expand_intrinsic_vaarg (callexp);
    827  1.1  mrg 
    828  1.1  mrg     case INTRINSIC_VASTART:
    829  1.1  mrg       return expand_intrinsic_vastart (callexp);
    830  1.1  mrg 
    831  1.1  mrg     case INTRINSIC_ADDS:
    832  1.1  mrg     case INTRINSIC_SUBS:
    833  1.1  mrg     case INTRINSIC_MULS:
    834  1.1  mrg     case INTRINSIC_NEGS:
    835  1.1  mrg       return expand_intrinsic_checkedint (intrinsic, callexp);
    836  1.1  mrg 
    837  1.1  mrg     case INTRINSIC_VLOAD:
    838  1.1  mrg       return expand_volatile_load (callexp);
    839  1.1  mrg 
    840  1.1  mrg     case INTRINSIC_VSTORE:
    841  1.1  mrg       return expand_volatile_store (callexp);
    842  1.1  mrg 
    843  1.1  mrg     default:
    844  1.1  mrg       gcc_unreachable ();
    845  1.1  mrg     }
    846  1.1  mrg }
    847