title: 256-bit vectorization via OpenMP SIMD prevents compiler's optimization (say function inlining)?
body: <p>Consider the following toy example, where <code>A</code> is an <code>n x 2</code> matrix stored in column-major order and I want to compute its column sum. <code>sum_0</code> only computes sum of the 1st column, while <code>sum_1</code> does the 2nd column as well. This is really an artificial example, as there is essentially no need to define two functions for this task (I can write a single function with a double loop nest where the outer loop iterates from <code>0</code> to <code>j</code>). It is constructed to demonstrate the template problem I have in reality.</p>
  
  <pre><code>/* "test.c" */
  #include &lt;stdlib.h&gt;
  
  // j can be 0 or 1
  static inline void sum_template (size_t j, size_t n, double *A, double *c) {
  
    if (n == 0) return;
    size_t i;
    double *a = A, *b = A + n;
    double c0 = 0.0, c1 = 0.0;
  
    #pragma omp simd reduction (+: c0, c1) aligned (a, b: 32)
    for (i = 0; i &lt; n; i++) {
      c0 += a[i];
      if (j &gt; 0) c1 += b[i];
      }
  
    c[0] = c0;
    if (j &gt; 0) c[1] = c1;
  
    }
  
  #define macro_define_sum(FUN, j)            \
  void FUN (size_t n, double *A, double *c) { \
    sum_template(j, n, A, c);                 \
    }
  
  macro_define_sum(sum_0, 0)
  macro_define_sum(sum_1, 1)
  </code></pre>
  
  <p>If I compile it with</p>
  
  <pre><code>gcc -O2 -mavx test.c
  </code></pre>
  
  <p>GCC (say the latest 8.2), after inlining, constant propagation and dead code elimination, would optimize out code involving <code>c1</code> for function <code>sum_0</code> (<a href="https://gcc.godbolt.org/z/IC896j" rel="nofollow noreferrer">Check it on Godbolt</a>).</p>
  
  <p>I like this trick. By writing a single template function and passing in different configuration parameters, an optimizing compiler can generate different versions. It is much cleaner than copying-and-pasting a big proportion of the code and manually define different function versions.</p>
  
  <p>However, such convenience is lost if I activate OpenMP 4.0+ with</p>
  
  <pre><code>gcc -O2 -mavx -fopenmp test.c
  </code></pre>
  
  <p><code>sum_template</code> is inlined no more and no dead code elimination is applied (<a href="https://gcc.godbolt.org/z/72SHoa" rel="nofollow noreferrer">Check it on Godbolt</a>). But if I remove flag <code>-mavx</code> to work with 128-bit SIMD, compiler optimization works as I expect (<a href="https://gcc.godbolt.org/z/Lr1hj7" rel="nofollow noreferrer">Check it on Godbolt</a>). So is this a bug? I am on an x86-64 (Sandybridge).</p>
  
  <hr>
  
  <p><strong>Remark</strong></p>
  
  <p>Using GCC's auto-vectorization <code>-ftree-vectorize -ffast-math</code> would not have this issue (<a href="https://gcc.godbolt.org/z/NveFNN" rel="nofollow noreferrer">Check it on Godbolt</a>). But I wish to use OpenMP because it allows portable alignment pragma across different compilers.</p>
  
  <p><strong>Background</strong></p>
  
  <p>I write modules for an R package, which needs be portable across platforms and compilers. Writing R extension requires no Makefile. When R is built on a platform, it knows what the default compiler is on that platform, and configures a set of default compilation flags. R does not have auto-vectorization flag but it has OpenMP flag. This means that using OpenMP SIMD is the ideal way to utilize SIMD in an R package. See <a href="https://stackoverflow.com/a/37214261/4891738">1</a> and <a href="https://stackoverflow.com/a/51682265/4891738">2</a> for a bit more elaboration.</p>