GCC preprocessor macro and "#pragma GCC unroll"

128 Views Asked by At

Is there another mechanism to get the GCC preprocessor to do this:

#define LIMIT  16
#pragma GCC unroll LIMIT
for (size_t ii = 0; ii < LIMIT; ++ii) {
  ...

That code hits an error:

/path/to/my/file.c:100:20 error: 'LIMIT' undeclared (first use in this function)
  100 | #pragma GCC unroll LIMIT
      |                    ^~~~~

gcc documentation says that this wants an integer constant expression specifying the unrolling factor. I believe that my macro is an "integer constant expression", but...

My compiler is: riscv64-unknown-elf-gcc (g2ee5e430018) 12.2.0.

3

There are 3 best solutions below

1
arch On BEST ANSWER

const and constexpr (in case you can use C++) seems to work (tested with gcc 13.2 on https://godbolt.org/).

const int x = 5;
#pragma GCC unroll x
for (std::size_t ii = 0; ii < x; ++ii) {
0
nielsen On

Instead of the #pragma directive, the _Pragma operator can be used. It is a bit tricky to get the argument expanded correctly, but this should work for both C and C++ (see example on godbolt.org):

#define STRING(V) #V
#define MAKE_PRAGMA(S) _Pragma(S)
#define UNROLL(N) MAKE_PRAGMA(STRING(GCC unroll N))

#define LIMIT 16
...
UNROLL(LIMIT)
for (size_t ii = 0; ii < LIMIT; ++ii) {
  ...
}
0
Jonathan Leffler On

Expanding on my comment.

The C11 standard §6.10.6 The #pragma directive says:

A preprocessing directive of the form

# pragma pp-tokens-opt new-line

where the preprocessing token STDC does not immediately follow pragma in the directive (prior to any macro replacement)174) causes the implementation to behave in an implementation-defined manner. The behavior might cause translation to fail or cause the translator or the resulting program to behave in a non-conforming manner. Any such pragma that is not recognized by the implementation is ignored.

If the preprocessing token STDC does immediately follow pragma in the directive (prior to any macro replacement), then no macro replacement is performed on the directive, and the directive shall have one of the following forms175) whose meanings are described elsewhere:

#pragma STDC FP_CONTRACT on-off-switch
#pragma STDC FENV_ACCESS on-off-switch
#pragma STDC CX_LIMITED_RANGE on-off-switch
on-off-switch: one of
            ON     OFF           DEFAULT

and footnote 174 says:

An implementation is not required to perform macro replacement in pragmas, but it is permitted except for in standard pragmas (where STDC immediately follows pragma). If the result of macro replacement in a non-standard pragma has the same form as a standard pragma, the behavior is still implementation-defined; an implementation is permitted to behave as if it were the standard pragma, but is not required to.

(Footnote 175 links to text reserving #pragma STDC … for future use by the standard.)

Footnote 174 is crucial. It means that GCC is within its rights not to attempt macro expansion; other compilers are within their rights if they do so. Both are compliant with the C standard.

  • Portable code cannot assume macro expansion will occur in a #pragma directive.

C23 and C18 say very much the same thing.

What you do about this depends on your requirements. However, generating a _Pragma operator (see §6.10.9 Pragma operator) is probably the best (most portable and reliable) way — as suggested by nielsen in their answer. An example in the standard shows building a string with macro replacement, etc.