Search code examples
cudamacrosc-preprocessorpreprocessornvcc

Incorrect number of arguments in preprocessor macro when passing CUDA kernel call as argument macro


I have the following macro

#define TIMEIT( variable, body ) \
variable = omp_get_wtime(); \
body; \
variable = omp_get_wtime() - variable;

which I use to very simply time sections of code. However, macro calls are sensitive to commas, and a CUDA kernel call (using the triple chevron syntax) causes the preprocessor to believe that the macro is being passed more than 2 arguments.

Is there a way around this?


Solution

  • Since C99/C++11, you can use a variadic argument (varargs) macro to solve this problem. You write a varargs macro using ... as the last parameter; in the body of the macro, __VA_ARGS__ will be replaced with the trailing arguments from the macro call, with commas intact:

    #define TIMEIT( variable, ... )   \
        variable = omp_get_wtime();   \
        __VA_ARGS__;                  \
        variable = omp_get_wtime() - variable;
    

    For compilers without varargs macro support, your only alternative is to try to protect all commas by using them only inside parenthetic expressions. Because parentheses protect commas from being treated as macro argument delimiters, many commas are naturally safe. But there are lots of exceptions, such as C++ template argument lists (<> doesn't protect commas), declarations of multiple objects, and -- as you say -- triple chevron calls. Some of these may be harder to protect than others.

    In particular, I don't know if you can put redundant parentheses around a CUDA kernel call, for example. Of course, if nvcc does handle varargs macros, you wouldn't need to. But based on this bug report, I'm not so sure. nvcc is based on the EDG compilet, which is conformant, but it does not seem to have occurred to nvidia to document which version of the standard is being used.