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