Home | History | Annotate | Line # | Download | only in gcc
      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