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