1 // GNU D Compiler attribute support declarations.
2 // Copyright (C) 2021 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.
Attribute(A...)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 
allSatisfy(alias F,T...)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  */
alloc_size(int sizeArgIdx)104 auto alloc_size(int sizeArgIdx)
105 {
106     return attribute("alloc_size", sizeArgIdx);
107 }
108 
109 /// ditto
alloc_size(int sizeArgIdx,int numArgIdx)110 auto alloc_size(int sizeArgIdx, int numArgIdx)
111 {
112     return attribute("alloc_size", sizeArgIdx, numArgIdx);
113 }
114 
115 /// ditto
alloc_size(int sizeArgIdx,int numArgIdx,bool zeroBasedNumbering)116 auto alloc_size(int sizeArgIdx, int numArgIdx, bool zeroBasedNumbering)
117 {
118     return attribute("alloc_size", sizeArgIdx, numArgIdx, zeroBasedNumbering);
119 }
120 
alloc_size(A...)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  */
section(string sectionName)309 auto section(string sectionName)
310 {
311     return attribute("section", sectionName);
312 }
313 
section(A...)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 
allocSize(A...)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  */
optStrategy(string strategy)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 
optStrategy(A...)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