Search code examples
c++openmppreprocessor-directiveunused-variables

Avoiding unused variable warnings with pre-compiler statements inside openmp parallel blocks


Background

My problem arises from a combination of a few particular things.

  1. I am using pre-processor statements to determine what kind of calculations to include in the produced executable
  2. I am using openmp parallel for blocks with default(none) (because I'm paranoid).
  3. The code compiles and runs properly, but can spew out unused variable warnings depending on the pre-processor flags. Not technically an error, but I would like to remove those warnings (and no, I don't just mean disabling the compiler warnings, but actually removing the cause i.e. the unused variables).

Essentially, I have something of the form

#pragma omp parallel \
  default(none) \
  shared(...) \
  private(...)
  {
  #pragma omp for
  for (i = 0; i < num_i; ++i) {

    compute_stuff;

    #if FLAG_1
      compute_more_stuff;
    #endif
    }
  }

Main issue

Suppose for clarity that variable x is only required if FLAG_1 is true. I could wrap the declaration for x and its usage within #if FLAG1 ... #endif statements, but I still need to list x within the variable list for the #pragma omp parallel, and, as far as I'm aware, I can't nest a #if FLAG1 ... #endif within the #pragma omp parallel statement (it's several lines long - there are a lot of variables). So, I either I get errors about non-existent variables listing in the pragma omp, or warnings about an unused variable.

Possible (but unsatisfying) solutions

  1. In this case the removed variables are all omp-private, and I acknowledge up front that simply replacing the default(none) with default(private) would resolve the problem. That said, I do like the coding practice of default(none), and would like to keep it if possible.

  2. Another option would be to simply break up the omp-parallel into something like the following, but compute_stuff and compute_more_stuff have some shared computations / memory access that I'd like the avoid duplicating.

#pragma omp parallel \
  default(none) \
  shared(...) \
  private(...)
  {
    #pragma omp for
    for (i = 0; i < num_i; ++i) {
      compute_stuff;
    }
  }

#if FLAG_1
#pragma omp parallel \
  default(none) \
  shared(...) \
  private(...)
  {
    #pragma omp for
    for (i = 0; i < num_i; ++i) {
      compute_more_stuff;
    }
  }
#endif

Any thoughts on how to maintain good coding practices while keep readable and efficient code would be greatly appreciated!


Solution

  • If you are using C++17, What's about the [[maybe_unused]] attribute?:

    #pragma omp parallel \
      default(none) \
      shared(...) \
      private(...)
      [[maybe_unused]] variable_potencially_not_used;
      {
      #pragma omp for
      for (i = 0; i < num_i; ++i) {
    
        compute_stuff;
    
        #if FLAG_1
          variable_potencially_not_used = 1;
        #endif
        }
      }
    

    If not, and alternative is to implement something similat to the Q_UNUSED macro. You can declare your own:

    #define MAYBE_UNUSED(X) (void)X
    #pragma omp parallel \
      default(none) \
      shared(...) \
      private(...)
      MAYBE_UNUSED(variable_potencially_not_used);
      {
      #pragma omp for
      for (i = 0; i < num_i; ++i) {
    
        compute_stuff;
    
        #if FLAG_1
          variable_potencially_not_used = 1;
        #endif
        }
      }```