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