1 // GNU D Compiler attribute support declarations. 2 // Copyright (C) 2021-2022 Free Software Foundation, Inc. 3 4 // GCC is free software; you can redistribute it and/or modify it under 5 // the terms of the GNU General Public License as published by the Free 6 // Software Foundation; either version 3, or (at your option) any later 7 // version. 8 9 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY 10 // WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 // for more details. 13 14 // Under Section 7 of GPL version 3, you are granted additional 15 // permissions described in the GCC Runtime Library Exception, version 16 // 3.1, as published by the Free Software Foundation. 17 18 // You should have received a copy of the GNU General Public License and 19 // a copy of the GCC Runtime Library Exception along with this program; 20 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21 // <http://www.gnu.org/licenses/>. 22 23 module gcc.attributes; 24 25 // Private helper templates. 26 private struct Attribute(A...) 27 { 28 A arguments; 29 } 30 31 private enum bool isStringValue(alias T) = is(typeof(T) == string); 32 33 private enum bool isStringOrIntValue(alias T) 34 = is(typeof(T) == string) || is(typeof(T) == int); 35 36 private template allSatisfy(alias F, T...) 37 { 38 static if (T.length == 0) 39 enum allSatisfy = true; 40 else static if (T.length == 1) 41 enum allSatisfy = F!(T[0]); 42 else 43 { 44 enum allSatisfy = allSatisfy!(F, T[ 0 .. $/2]) 45 && allSatisfy!(F, T[$/2 .. $ ]); 46 } 47 } 48 49 /** 50 * Generic entrypoint for applying GCC attributes to a function or type. 51 * There is no type checking done, as well as no deprecation path for 52 * attributes removed from the compiler. So the recommendation is to use any 53 , of the other UDAs available unless it is a target-specific attribute. 54 * 55 * Function attributes introduced by the @attribute UDA are used in the 56 * declaration of a function, followed by an attribute name string and 57 * any arguments separated by commas enclosed in parentheses. 58 * 59 * Example: 60 * --- 61 * import gcc.attributes; 62 * 63 * @attribute("regparm", 1) int func(int size); 64 * --- 65 */ 66 @system 67 auto attribute(A...)(A arguments) 68 if (A.length > 0 && is(A[0] == string)) 69 { 70 return Attribute!A(arguments); 71 } 72 73 74 /////////////////////////////////////////////////////////////////////////////// 75 // 76 // Supported common attributes exposed by GDC. 77 // 78 /////////////////////////////////////////////////////////////////////////////// 79 80 /** 81 * The `@alloc_size` attribute may be applied to a function that returns a 82 * pointer and takes at least one argument of an integer or enumerated type. 83 * It indicates that the returned pointer points to memory whose size is given 84 * by the function argument at `sizeArgIdx`, or by the product of the arguments 85 * at `sizeArgIdx` and `numArgIdx`. Meaningful sizes are positive values less 86 * than `ptrdiff_t.max`. Unless `zeroBasedNumbering` is true, argument 87 * numbering starts at one for ordinary functions, and at two for non-static 88 * member functions. 89 * 90 * If `numArgIdx` is less than `0`, it is taken to mean there is no argument 91 * specifying the element count. 92 * 93 * Example: 94 * --- 95 * import gcc.attributes; 96 * 97 * @alloc_size(1) extern(C) void* malloc(size_t size); 98 * @alloc_size(3,2) extern(C) void* reallocarray(void *ptr, size_t nmemb, 99 * size_t size); 100 * @alloc_size(1,2) void* my_calloc(size_t element_size, size_t count, 101 * bool irrelevant); 102 * --- 103 */ 104 auto alloc_size(int sizeArgIdx) 105 { 106 return attribute("alloc_size", sizeArgIdx); 107 } 108 109 /// ditto 110 auto alloc_size(int sizeArgIdx, int numArgIdx) 111 { 112 return attribute("alloc_size", sizeArgIdx, numArgIdx); 113 } 114 115 /// ditto 116 auto alloc_size(int sizeArgIdx, int numArgIdx, bool zeroBasedNumbering) 117 { 118 return attribute("alloc_size", sizeArgIdx, numArgIdx, zeroBasedNumbering); 119 } 120 121 auto alloc_size(A...)(A arguments) 122 { 123 assert(false, "alloc_size attribute argument value is not an integer constant"); 124 } 125 126 /** 127 * The `@always_inline` attribute inlines the function independent of any 128 * restrictions that otherwise apply to inlining. Failure to inline such a 129 * function is diagnosed as an error. 130 * 131 * Example: 132 * --- 133 * import gcc.attributes; 134 * 135 * @always_inline int func(); 136 * --- 137 */ 138 enum always_inline = attribute("always_inline"); 139 140 /** 141 * The `@cold` attribute on functions is used to inform the compiler that the 142 * function is unlikely to be executed. The function is optimized for size 143 * rather than speed and on many targets it is placed into a special subsection 144 * of the text section so all cold functions appear close together, improving 145 * code locality of non-cold parts of program. The paths leading to calls of 146 * cold functions within code are considered to be cold too. 147 * 148 * Example: 149 * --- 150 * import gcc.attributes; 151 * 152 * @cold int func(); 153 * --- 154 */ 155 enum cold = attribute("cold"); 156 157 /** 158 * The `@flatten` attribute is used to inform the compiler that every call 159 * inside this function should be inlined, if possible. Functions declared with 160 * attribute `@noinline` and similar are not inlined. 161 * 162 * Example: 163 * --- 164 * import gcc.attributes; 165 * 166 * @flatten int func(); 167 * --- 168 */ 169 enum flatten = attribute("flatten"); 170 171 /** 172 * The `@no_icf` attribute prevents a functions from being merged with another 173 * semantically equivalent function. 174 * 175 * Example: 176 * --- 177 * import gcc.attributes; 178 * 179 * @no_icf int func(); 180 * --- 181 */ 182 enum no_icf = attribute("no_icf"); 183 184 /** 185 * The `@noclone` attribute prevents a function from being considered for 186 * cloning - a mechanism that produces specialized copies of functions and 187 * which is (currently) performed by interprocedural constant propagation. 188 * 189 * Example: 190 * --- 191 * import gcc.attributes; 192 * 193 * @noclone int func(); 194 * --- 195 */ 196 enum noclone = attribute("noclone"); 197 198 /** 199 * The `@noinline` attribute prevents a function from being considered for 200 * inlining. If the function does not have side effects, there are 201 * optimizations other than inlining that cause function calls to be optimized 202 * away, although the function call is live. To keep such calls from being 203 * optimized away, put `asm { ""; }` in the called function, to serve as a 204 * special side effect. 205 * 206 * Example: 207 * --- 208 * import gcc.attributes; 209 * 210 * @noinline int func(); 211 * --- 212 */ 213 enum noinline = attribute("noinline"); 214 215 /** 216 * The `@noipa` attribute disables interprocedural optimizations between the 217 * function with this attribute and its callers, as if the body of the function 218 * is not available when optimizing callers and the callers are unavailable when 219 * optimizing the body. This attribute implies `@noinline`, `@noclone`, and 220 * `@no_icf` attributes. However, this attribute is not equivalent to a 221 * combination of other attributes, because its purpose is to suppress existing 222 * and future optimizations employing interprocedural analysis, including those 223 * that do not have an attribute suitable for disabling them individually. 224 * 225 * This attribute is supported mainly for the purpose of testing the compiler. 226 * 227 * Example: 228 * --- 229 * import gcc.attributes; 230 * 231 * @noipa int func(); 232 * --- 233 */ 234 enum noipa = attribute("noipa"); 235 236 /** 237 * The `@optimize` attribute is used to specify that a function is to be 238 * compiled with different optimization options than specified on the command 239 * line. Valid `arguments` are constant non-negative integers and strings. 240 * Multiple arguments can be provided, separated by commas to specify multiple 241 * options. Each numeric argument specifies an optimization level. Each string 242 * argument that begins with the letter O refers to an optimization option such 243 * as `-O0` or `-Os`. Other options are taken as suffixes to the `-f` prefix 244 * jointly forming the name of an optimization option. 245 * 246 * Not every optimization option that starts with the `-f` prefix specified by 247 * the attribute necessarily has an effect on the function. The `@optimize` 248 * attribute should be used for debugging purposes only. It is not suitable in 249 * production code. 250 * 251 * Example: 252 * --- 253 * import gcc.attributes; 254 * 255 * @optimize(2) double fn0(double x); 256 * @optimize("2") double fn1(double x); 257 * @optimize("s") double fn2(double x); 258 * @optimize("Ofast") double fn3(double x); 259 * @optimize("-O2") double fn4(double x); 260 * @optimize("tree-vectorize") double fn5(double x); 261 * @optimize("-ftree-vectorize") double fn6(double x); 262 * @optimize("no-finite-math-only", 3) double fn7(double x); 263 * --- 264 */ 265 auto optimize(A...)(A arguments) 266 if (allSatisfy!(isStringOrIntValue, arguments)) 267 { 268 return attribute("optimize", arguments); 269 } 270 271 auto optimize(A...)(A arguments) 272 if (!allSatisfy!(isStringOrIntValue, arguments)) 273 { 274 assert(false, "optimize attribute argument not a string or integer constant"); 275 } 276 277 /** 278 * The `@restrict` attribute specifies that a function parameter is to be 279 * restrict-qualified in the C99 sense of the term. The parameter needs to 280 * boil down to either a pointer or reference type, such as a D pointer, 281 * class reference, or a `ref` parameter. 282 * 283 * Example: 284 * --- 285 * import gcc.attributes; 286 * 287 * void func(@restrict ref const float[16] array); 288 * --- 289 */ 290 enum restrict = attribute("restrict"); 291 292 /** 293 * The `@section` attribute specifies that a function lives in a particular 294 * section. For when you need certain particular functions to appear in 295 * special sections. 296 * 297 * Some file formats do not support arbitrary sections so the section attribute 298 * is not available on all platforms. If you need to map the entire contents 299 * of a module to a particular section, consider using the facilities of the 300 * linker instead. 301 * 302 * Example: 303 * --- 304 * import gcc.attributes; 305 * 306 * @section("bar") extern void func(); 307 * --- 308 */ 309 auto section(string sectionName) 310 { 311 return attribute("section", sectionName); 312 } 313 314 auto section(A...)(A arguments) 315 { 316 assert(false, "section attribute argument not a string constant"); 317 } 318 319 /** 320 * The `@symver` attribute creates a symbol version on ELF targets. The syntax 321 * of the string parameter is `name@nodename`. The `name` part of the parameter 322 * is the actual name of the symbol by which it will be externally referenced. 323 * The `nodename` portion should be the name of a node specified in the version 324 * script supplied to the linker when building a shared library. Versioned 325 * symbol must be defined and must be exported with default visibility. 326 * 327 * Finally if the parameter is `name@@nodename` then in addition to creating a 328 * symbol version (as if `name@nodename` was used) the version will be also used 329 * to resolve `name` by the linker. 330 * 331 * Example: 332 * --- 333 * import gcc.attributes; 334 * 335 * @symver("foo@VERS_1") int foo_v1(); 336 * --- 337 */ 338 auto symver(A...)(A arguments) 339 if (allSatisfy!(isStringValue, arguments)) 340 { 341 return attribute("symver", arguments); 342 } 343 344 auto symver(A...)(A arguments) 345 if (!allSatisfy!(isStringValue, arguments)) 346 { 347 assert(false, "symver attribute argument not a string constant"); 348 } 349 350 /** 351 * The `@target` attribute is used to specify that a function is to be 352 * compiled with different target options than specified on the command line. 353 * One or more strings can be provided as arguments, separated by commas to 354 * specify multiple options. Each string consists of one or more 355 * comma-separated suffixes to the `-m` prefix jointly forming the name of a 356 * machine-dependent option. 357 * 358 * The target attribute can be used for instance to have a function compiled 359 * with a different ISA (instruction set architecture) than the default. 360 * 361 * The options supported are specific to each target. 362 * 363 * Example: 364 * --- 365 * import gcc.attributes; 366 * 367 * @target("arch=core2") void core2_func(); 368 * @target("sse3") void sse3_func(); 369 * --- 370 */ 371 auto target(A...)(A arguments) 372 if (allSatisfy!(isStringValue, arguments)) 373 { 374 return attribute("target", arguments); 375 } 376 377 auto target(A...)(A arguments) 378 if (!allSatisfy!(isStringValue, arguments)) 379 { 380 assert(false, "target attribute argument not a string constant"); 381 } 382 383 /** 384 * The `@target_clones` attribute is used to specify that a function be cloned 385 * into multiple versions compiled with different target `options` than 386 * specified on the command line. The supported options and restrictions are 387 * the same as for `@target` attribute. 388 * 389 * It also creates a resolver function that dynamically selects a clone suitable 390 * for current architecture. The resolver is created only if there is a usage 391 * of a function with `@target_clones` attribute. 392 * 393 * Example: 394 * --- 395 * import gcc.attributes; 396 * 397 * @target_clones("sse4.1,avx,default") double func(double x); 398 * --- 399 */ 400 auto target_clones(A...)(A arguments) 401 if (allSatisfy!(isStringValue, arguments)) 402 { 403 return attribute("target_clones", arguments); 404 } 405 406 auto target_clones(A...)(A arguments) 407 if (!allSatisfy!(isStringValue, arguments)) 408 { 409 assert(false, "target attribute argument not a string constant"); 410 } 411 412 /** 413 * The `@used` attribute, annotated to a function, means that code must be 414 * emitted for the function even if it appears that the function is not 415 * referenced. This is useful, for example, when the function is referenced 416 * only in inline assembly. 417 * 418 * Example: 419 * --- 420 * import gcc.attributes; 421 * 422 * @used __gshared int var = 0x1000; 423 * --- 424 */ 425 enum used = attribute("used"); 426 427 /** 428 * The `@weak` attribute causes a declaration of an external symbol to be 429 * emitted as a weak symbol rather than a global. This is primarily useful in 430 * defining library functions that can be overridden in user code, though it can 431 * also be used with non-function declarations. The overriding symbol must have 432 * the same type as the weak symbol. In addition, if it designates a variable 433 * it must also have the same size and alignment as the weak symbol. 434 * 435 * Weak symbols are supported for ELF targets, and also for a.out targets when 436 * using the GNU assembler and linker. 437 * 438 * Example: 439 * --- 440 * import gcc.attributes; 441 * 442 * @weak int func() { return 1; } 443 * --- 444 */ 445 enum weak = attribute("weak"); 446 447 /** 448 * The `@noplt` attribute is the counterpart to option `-fno-plt`. Calls to 449 * functions marked with this attribute in position-independent code do not use 450 * the PLT in position-independent code. 451 * 452 * In position-dependant code, a few targets also convert call to functions 453 * that are marked to not use the PLT to use the GOT instead. 454 * 455 * Example: 456 * --- 457 * import gcc.attributes; 458 * 459 * @noplt int func(); 460 * 461 * --- 462 */ 463 enum noplt = attribute("noplt"); 464 465 /////////////////////////////////////////////////////////////////////////////// 466 // 467 // Attributes defined for compatibility with LDC. 468 // 469 /////////////////////////////////////////////////////////////////////////////// 470 471 /** 472 * Specifies that the function returns `null` or a pointer to at least a 473 * certain number of allocated bytes. `sizeArgIdx` and `numArgIdx` specify 474 * the 0-based index of the function arguments that should be used to calculate 475 * the number of bytes returned. 476 * 477 * Example: 478 * --- 479 * import gcc.attributes; 480 * 481 * @allocSize(0) extern(C) void* malloc(size_t size); 482 * @allocSize(2,1) extern(C) void* reallocarray(void *ptr, size_t nmemb, 483 * size_t size); 484 * @allocSize(0,1) void* my_calloc(size_t element_size, size_t count, 485 * bool irrelevant); 486 * --- 487 */ 488 auto allocSize(int sizeArgIdx, int numArgIdx = int.min) 489 { 490 return alloc_size(sizeArgIdx, numArgIdx, true); 491 } 492 493 auto allocSize(A...)(A arguments) 494 { 495 assert(false, "allocSize attribute argument value is not an integer constant"); 496 } 497 498 /** 499 * When applied to a global symbol, the compiler, assembler, and linker are 500 * required to treat the symbol as if there is a reference to the symbol that 501 * it cannot see (which is why they have to be named). For example, it 502 * prevents the deletion by the linker of an unreferenced symbol. 503 * 504 * Example: 505 * --- 506 * import gcc.attributes; 507 * 508 * @assumeUsed __gshared int var = 0x1000; 509 * --- 510 */ 511 alias assumeUsed = used; 512 513 /// This attribute has no effect. 514 enum dynamicCompile = false; 515 516 /// ditto 517 enum dynamicCompileConst = false; 518 519 /// ditto 520 enum dynamicCompileEmit = false; 521 522 /** 523 * Explicitly sets "fast-math" for a function, enabling aggressive math 524 * optimizations. These optimizations may dramatically change the outcome of 525 * floating point calculations (e.g. because of reassociation). 526 * 527 * Example: 528 * --- 529 * import gcc.attributes; 530 * 531 * @fastmath 532 * double dot(double[] a, double[] b) { 533 * double s = 0; 534 * foreach(size_t i; 0..a.length) 535 * { 536 * // will result in vectorized fused-multiply-add instructions 537 * s += a * b; 538 * } 539 * return s; 540 * } 541 * --- 542 */ 543 enum fastmath = optimize("Ofast"); 544 545 /** 546 * Adds GCC's "naked" attribute to a function, disabling function prologue / 547 * epilogue emission. 548 * Intended to be used in combination with basic `asm` statement. While using 549 * extended `asm` or a mixture of basic `asm` and D code may appear to work, 550 * they cannot be depended upon to work reliably and are not supported. 551 * 552 * Example: 553 * --- 554 * import gcc.attributes; 555 * 556 * @naked void abort() { 557 * asm { "ud2"; } 558 * } 559 * --- 560 */ 561 enum naked = attribute("naked"); 562 563 /** 564 * Sets the optimization strategy for a function. 565 * Valid strategies are "none", "optsize", "minsize". The strategies are 566 * mutually exclusive. 567 * 568 * Example: 569 * --- 570 * import gcc.attributes; 571 * 572 * @optStrategy("none") 573 * int func() { 574 * return call(); 575 * } 576 * --- 577 */ 578 auto optStrategy(string strategy) 579 { 580 if (strategy == "none") 581 return optimize("O0"); 582 else if (strategy == "optsize" || strategy == "minsize") 583 return optimize("Os"); 584 else 585 { 586 assert(false, "unrecognized parameter `" ~ strategy 587 ~ "` for `gcc.attribute.optStrategy`"); 588 } 589 } 590 591 auto optStrategy(A...)(A arguments) 592 { 593 assert(false, "optStrategy attribute argument value is not a string constant"); 594 } 595 596 /** 597 * When applied to a function, specifies that the function should be optimzed 598 * by Graphite, GCC's polyhedral optimizer. Useful for optimizing loops for 599 * data locality, vectorization and parallelism. 600 * 601 * Experimental! 602 * 603 * Only effective when GDC was built with ISL included. 604 */ 605 enum polly = optimize("loop-parallelize-all", "loop-nest-optimize"); 606