| // GNU D Compiler attribute support declarations. |
| // Copyright (C) 2021-2022 Free Software Foundation, Inc. |
| |
| // GCC is free software; you can redistribute it and/or modify it under |
| // the terms of the GNU General Public License as published by the Free |
| // Software Foundation; either version 3, or (at your option) any later |
| // version. |
| |
| // GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| // for more details. |
| |
| // Under Section 7 of GPL version 3, you are granted additional |
| // permissions described in the GCC Runtime Library Exception, version |
| // 3.1, as published by the Free Software Foundation. |
| |
| // You should have received a copy of the GNU General Public License and |
| // a copy of the GCC Runtime Library Exception along with this program; |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| // <http://www.gnu.org/licenses/>. |
| |
| module gcc.attributes; |
| |
| // Private helper templates. |
| private struct Attribute(A...) |
| { |
| A arguments; |
| } |
| |
| private enum bool isStringValue(alias T) = is(typeof(T) == string); |
| |
| private enum bool isStringOrIntValue(alias T) |
| = is(typeof(T) == string) || is(typeof(T) == int); |
| |
| private template allSatisfy(alias F, T...) |
| { |
| static if (T.length == 0) |
| enum allSatisfy = true; |
| else static if (T.length == 1) |
| enum allSatisfy = F!(T[0]); |
| else |
| { |
| enum allSatisfy = allSatisfy!(F, T[ 0 .. $/2]) |
| && allSatisfy!(F, T[$/2 .. $ ]); |
| } |
| } |
| |
| /** |
| * Generic entrypoint for applying GCC attributes to a function or type. |
| * There is no type checking done, as well as no deprecation path for |
| * attributes removed from the compiler. So the recommendation is to use any |
| , of the other UDAs available unless it is a target-specific attribute. |
| * |
| * Function attributes introduced by the @attribute UDA are used in the |
| * declaration of a function, followed by an attribute name string and |
| * any arguments separated by commas enclosed in parentheses. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @attribute("regparm", 1) int func(int size); |
| * --- |
| */ |
| @system |
| auto attribute(A...)(A arguments) |
| if (A.length > 0 && is(A[0] == string)) |
| { |
| return Attribute!A(arguments); |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Supported common attributes exposed by GDC. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * The `@alloc_size` attribute may be applied to a function that returns a |
| * pointer and takes at least one argument of an integer or enumerated type. |
| * It indicates that the returned pointer points to memory whose size is given |
| * by the function argument at `sizeArgIdx`, or by the product of the arguments |
| * at `sizeArgIdx` and `numArgIdx`. Meaningful sizes are positive values less |
| * than `ptrdiff_t.max`. Unless `zeroBasedNumbering` is true, argument |
| * numbering starts at one for ordinary functions, and at two for non-static |
| * member functions. |
| * |
| * If `numArgIdx` is less than `0`, it is taken to mean there is no argument |
| * specifying the element count. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @alloc_size(1) extern(C) void* malloc(size_t size); |
| * @alloc_size(3,2) extern(C) void* reallocarray(void *ptr, size_t nmemb, |
| * size_t size); |
| * @alloc_size(1,2) void* my_calloc(size_t element_size, size_t count, |
| * bool irrelevant); |
| * --- |
| */ |
| auto alloc_size(int sizeArgIdx) |
| { |
| return attribute("alloc_size", sizeArgIdx); |
| } |
| |
| /// ditto |
| auto alloc_size(int sizeArgIdx, int numArgIdx) |
| { |
| return attribute("alloc_size", sizeArgIdx, numArgIdx); |
| } |
| |
| /// ditto |
| auto alloc_size(int sizeArgIdx, int numArgIdx, bool zeroBasedNumbering) |
| { |
| return attribute("alloc_size", sizeArgIdx, numArgIdx, zeroBasedNumbering); |
| } |
| |
| auto alloc_size(A...)(A arguments) |
| { |
| assert(false, "alloc_size attribute argument value is not an integer constant"); |
| } |
| |
| /** |
| * The `@always_inline` attribute inlines the function independent of any |
| * restrictions that otherwise apply to inlining. Failure to inline such a |
| * function is diagnosed as an error. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @always_inline int func(); |
| * --- |
| */ |
| enum always_inline = attribute("always_inline"); |
| |
| /** |
| * The `@cold` attribute on functions is used to inform the compiler that the |
| * function is unlikely to be executed. The function is optimized for size |
| * rather than speed and on many targets it is placed into a special subsection |
| * of the text section so all cold functions appear close together, improving |
| * code locality of non-cold parts of program. The paths leading to calls of |
| * cold functions within code are considered to be cold too. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @cold int func(); |
| * --- |
| */ |
| enum cold = attribute("cold"); |
| |
| /** |
| * The `@flatten` attribute is used to inform the compiler that every call |
| * inside this function should be inlined, if possible. Functions declared with |
| * attribute `@noinline` and similar are not inlined. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @flatten int func(); |
| * --- |
| */ |
| enum flatten = attribute("flatten"); |
| |
| /** |
| * The `@no_icf` attribute prevents a functions from being merged with another |
| * semantically equivalent function. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @no_icf int func(); |
| * --- |
| */ |
| enum no_icf = attribute("no_icf"); |
| |
| /** |
| * The `@noclone` attribute prevents a function from being considered for |
| * cloning - a mechanism that produces specialized copies of functions and |
| * which is (currently) performed by interprocedural constant propagation. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @noclone int func(); |
| * --- |
| */ |
| enum noclone = attribute("noclone"); |
| |
| /** |
| * The `@noinline` attribute prevents a function from being considered for |
| * inlining. If the function does not have side effects, there are |
| * optimizations other than inlining that cause function calls to be optimized |
| * away, although the function call is live. To keep such calls from being |
| * optimized away, put `asm { ""; }` in the called function, to serve as a |
| * special side effect. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @noinline int func(); |
| * --- |
| */ |
| enum noinline = attribute("noinline"); |
| |
| /** |
| * The `@noipa` attribute disables interprocedural optimizations between the |
| * function with this attribute and its callers, as if the body of the function |
| * is not available when optimizing callers and the callers are unavailable when |
| * optimizing the body. This attribute implies `@noinline`, `@noclone`, and |
| * `@no_icf` attributes. However, this attribute is not equivalent to a |
| * combination of other attributes, because its purpose is to suppress existing |
| * and future optimizations employing interprocedural analysis, including those |
| * that do not have an attribute suitable for disabling them individually. |
| * |
| * This attribute is supported mainly for the purpose of testing the compiler. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @noipa int func(); |
| * --- |
| */ |
| enum noipa = attribute("noipa"); |
| |
| /** |
| * The `@optimize` attribute is used to specify that a function is to be |
| * compiled with different optimization options than specified on the command |
| * line. Valid `arguments` are constant non-negative integers and strings. |
| * Multiple arguments can be provided, separated by commas to specify multiple |
| * options. Each numeric argument specifies an optimization level. Each string |
| * argument that begins with the letter O refers to an optimization option such |
| * as `-O0` or `-Os`. Other options are taken as suffixes to the `-f` prefix |
| * jointly forming the name of an optimization option. |
| * |
| * Not every optimization option that starts with the `-f` prefix specified by |
| * the attribute necessarily has an effect on the function. The `@optimize` |
| * attribute should be used for debugging purposes only. It is not suitable in |
| * production code. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @optimize(2) double fn0(double x); |
| * @optimize("2") double fn1(double x); |
| * @optimize("s") double fn2(double x); |
| * @optimize("Ofast") double fn3(double x); |
| * @optimize("-O2") double fn4(double x); |
| * @optimize("tree-vectorize") double fn5(double x); |
| * @optimize("-ftree-vectorize") double fn6(double x); |
| * @optimize("no-finite-math-only", 3) double fn7(double x); |
| * --- |
| */ |
| auto optimize(A...)(A arguments) |
| if (allSatisfy!(isStringOrIntValue, arguments)) |
| { |
| return attribute("optimize", arguments); |
| } |
| |
| auto optimize(A...)(A arguments) |
| if (!allSatisfy!(isStringOrIntValue, arguments)) |
| { |
| assert(false, "optimize attribute argument not a string or integer constant"); |
| } |
| |
| /** |
| * The `@restrict` attribute specifies that a function parameter is to be |
| * restrict-qualified in the C99 sense of the term. The parameter needs to |
| * boil down to either a pointer or reference type, such as a D pointer, |
| * class reference, or a `ref` parameter. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * void func(@restrict ref const float[16] array); |
| * --- |
| */ |
| enum restrict = attribute("restrict"); |
| |
| /** |
| * The `@section` attribute specifies that a function lives in a particular |
| * section. For when you need certain particular functions to appear in |
| * special sections. |
| * |
| * Some file formats do not support arbitrary sections so the section attribute |
| * is not available on all platforms. If you need to map the entire contents |
| * of a module to a particular section, consider using the facilities of the |
| * linker instead. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @section("bar") extern void func(); |
| * --- |
| */ |
| auto section(string sectionName) |
| { |
| return attribute("section", sectionName); |
| } |
| |
| auto section(A...)(A arguments) |
| { |
| assert(false, "section attribute argument not a string constant"); |
| } |
| |
| /** |
| * The `@symver` attribute creates a symbol version on ELF targets. The syntax |
| * of the string parameter is `name@nodename`. The `name` part of the parameter |
| * is the actual name of the symbol by which it will be externally referenced. |
| * The `nodename` portion should be the name of a node specified in the version |
| * script supplied to the linker when building a shared library. Versioned |
| * symbol must be defined and must be exported with default visibility. |
| * |
| * Finally if the parameter is `name@@nodename` then in addition to creating a |
| * symbol version (as if `name@nodename` was used) the version will be also used |
| * to resolve `name` by the linker. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @symver("foo@VERS_1") int foo_v1(); |
| * --- |
| */ |
| auto symver(A...)(A arguments) |
| if (allSatisfy!(isStringValue, arguments)) |
| { |
| return attribute("symver", arguments); |
| } |
| |
| auto symver(A...)(A arguments) |
| if (!allSatisfy!(isStringValue, arguments)) |
| { |
| assert(false, "symver attribute argument not a string constant"); |
| } |
| |
| /** |
| * The `@target` attribute is used to specify that a function is to be |
| * compiled with different target options than specified on the command line. |
| * One or more strings can be provided as arguments, separated by commas to |
| * specify multiple options. Each string consists of one or more |
| * comma-separated suffixes to the `-m` prefix jointly forming the name of a |
| * machine-dependent option. |
| * |
| * The target attribute can be used for instance to have a function compiled |
| * with a different ISA (instruction set architecture) than the default. |
| * |
| * The options supported are specific to each target. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @target("arch=core2") void core2_func(); |
| * @target("sse3") void sse3_func(); |
| * --- |
| */ |
| auto target(A...)(A arguments) |
| if (allSatisfy!(isStringValue, arguments)) |
| { |
| return attribute("target", arguments); |
| } |
| |
| auto target(A...)(A arguments) |
| if (!allSatisfy!(isStringValue, arguments)) |
| { |
| assert(false, "target attribute argument not a string constant"); |
| } |
| |
| /** |
| * The `@target_clones` attribute is used to specify that a function be cloned |
| * into multiple versions compiled with different target `options` than |
| * specified on the command line. The supported options and restrictions are |
| * the same as for `@target` attribute. |
| * |
| * It also creates a resolver function that dynamically selects a clone suitable |
| * for current architecture. The resolver is created only if there is a usage |
| * of a function with `@target_clones` attribute. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @target_clones("sse4.1,avx,default") double func(double x); |
| * --- |
| */ |
| auto target_clones(A...)(A arguments) |
| if (allSatisfy!(isStringValue, arguments)) |
| { |
| return attribute("target_clones", arguments); |
| } |
| |
| auto target_clones(A...)(A arguments) |
| if (!allSatisfy!(isStringValue, arguments)) |
| { |
| assert(false, "target attribute argument not a string constant"); |
| } |
| |
| /** |
| * The `@used` attribute, annotated to a function, means that code must be |
| * emitted for the function even if it appears that the function is not |
| * referenced. This is useful, for example, when the function is referenced |
| * only in inline assembly. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @used __gshared int var = 0x1000; |
| * --- |
| */ |
| enum used = attribute("used"); |
| |
| /** |
| * The `@weak` attribute causes a declaration of an external symbol to be |
| * emitted as a weak symbol rather than a global. This is primarily useful in |
| * defining library functions that can be overridden in user code, though it can |
| * also be used with non-function declarations. The overriding symbol must have |
| * the same type as the weak symbol. In addition, if it designates a variable |
| * it must also have the same size and alignment as the weak symbol. |
| * |
| * Weak symbols are supported for ELF targets, and also for a.out targets when |
| * using the GNU assembler and linker. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @weak int func() { return 1; } |
| * --- |
| */ |
| enum weak = attribute("weak"); |
| |
| /** |
| * The `@noplt` attribute is the counterpart to option `-fno-plt`. Calls to |
| * functions marked with this attribute in position-independent code do not use |
| * the PLT in position-independent code. |
| * |
| * In position-dependant code, a few targets also convert call to functions |
| * that are marked to not use the PLT to use the GOT instead. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @noplt int func(); |
| * |
| * --- |
| */ |
| enum noplt = attribute("noplt"); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Attributes defined for compatibility with LDC. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Specifies that the function returns `null` or a pointer to at least a |
| * certain number of allocated bytes. `sizeArgIdx` and `numArgIdx` specify |
| * the 0-based index of the function arguments that should be used to calculate |
| * the number of bytes returned. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @allocSize(0) extern(C) void* malloc(size_t size); |
| * @allocSize(2,1) extern(C) void* reallocarray(void *ptr, size_t nmemb, |
| * size_t size); |
| * @allocSize(0,1) void* my_calloc(size_t element_size, size_t count, |
| * bool irrelevant); |
| * --- |
| */ |
| auto allocSize(int sizeArgIdx, int numArgIdx = int.min) |
| { |
| return alloc_size(sizeArgIdx, numArgIdx, true); |
| } |
| |
| auto allocSize(A...)(A arguments) |
| { |
| assert(false, "allocSize attribute argument value is not an integer constant"); |
| } |
| |
| /** |
| * When applied to a global symbol, the compiler, assembler, and linker are |
| * required to treat the symbol as if there is a reference to the symbol that |
| * it cannot see (which is why they have to be named). For example, it |
| * prevents the deletion by the linker of an unreferenced symbol. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @assumeUsed __gshared int var = 0x1000; |
| * --- |
| */ |
| alias assumeUsed = used; |
| |
| /// This attribute has no effect. |
| enum dynamicCompile = false; |
| |
| /// ditto |
| enum dynamicCompileConst = false; |
| |
| /// ditto |
| enum dynamicCompileEmit = false; |
| |
| /** |
| * Explicitly sets "fast-math" for a function, enabling aggressive math |
| * optimizations. These optimizations may dramatically change the outcome of |
| * floating point calculations (e.g. because of reassociation). |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @fastmath |
| * double dot(double[] a, double[] b) { |
| * double s = 0; |
| * foreach(size_t i; 0..a.length) |
| * { |
| * // will result in vectorized fused-multiply-add instructions |
| * s += a * b; |
| * } |
| * return s; |
| * } |
| * --- |
| */ |
| enum fastmath = optimize("Ofast"); |
| |
| /** |
| * Adds GCC's "naked" attribute to a function, disabling function prologue / |
| * epilogue emission. |
| * Intended to be used in combination with basic `asm` statement. While using |
| * extended `asm` or a mixture of basic `asm` and D code may appear to work, |
| * they cannot be depended upon to work reliably and are not supported. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @naked void abort() { |
| * asm { "ud2"; } |
| * } |
| * --- |
| */ |
| enum naked = attribute("naked"); |
| |
| /** |
| * Sets the optimization strategy for a function. |
| * Valid strategies are "none", "optsize", "minsize". The strategies are |
| * mutually exclusive. |
| * |
| * Example: |
| * --- |
| * import gcc.attributes; |
| * |
| * @optStrategy("none") |
| * int func() { |
| * return call(); |
| * } |
| * --- |
| */ |
| auto optStrategy(string strategy) |
| { |
| if (strategy == "none") |
| return optimize("O0"); |
| else if (strategy == "optsize" || strategy == "minsize") |
| return optimize("Os"); |
| else |
| { |
| assert(false, "unrecognized parameter `" ~ strategy |
| ~ "` for `gcc.attribute.optStrategy`"); |
| } |
| } |
| |
| auto optStrategy(A...)(A arguments) |
| { |
| assert(false, "optStrategy attribute argument value is not a string constant"); |
| } |
| |
| /** |
| * When applied to a function, specifies that the function should be optimzed |
| * by Graphite, GCC's polyhedral optimizer. Useful for optimizing loops for |
| * data locality, vectorization and parallelism. |
| * |
| * Experimental! |
| * |
| * Only effective when GDC was built with ISL included. |
| */ |
| enum polly = optimize("loop-parallelize-all", "loop-nest-optimize"); |