“私有变量不能被还原”,尽管该变量是在SIMD块之外定义的

问题描述:

我有一个使用OpenMP的C++项目,我尝试使用Blue Gene/Q上的LLVM进行编译。还有一个功能,剥离下来的,看起来是这样的:“私有变量不能被还原”,尽管该变量是在SIMD块之外定义的

template <typename FT, int veclen> 
inline void xmyNorm2Spinor(FT *res, 
          FT *x, 
          FT *y, 
          double &n2res, 
          int n, 
          int n_cores, 
          int n_simt, 
          int n_blas_simt) { 
#if defined(__GNUG__) && !defined(__INTEL_COMPILER) 
    double norm2res __attribute__((aligned(QPHIX_LLC_CACHE_ALIGN))) = 0; 
#else 
    __declspec(align(QPHIX_LLC_CACHE_ALIGN)) double norm2res = 0; 
#endif 

#pragma omp parallel shared(norm_array) 
    { 
     // […] 
     if (smtid < n_blas_simt) { 
      // […] 

      double lnorm = 0; 

//#pragma prefetch x,y,res 
//#pragma vector aligned(x,y,res) 
#pragma omp simd aligned(res, x, y : veclen) reduction(+ : lnorm) 
      for (int i = low; i < hi; i++) { 
       res[i] = x[i] - y[i]; 
       double tmpd = (double)res[i]; 
       lnorm += (tmpd * tmpd); 
      } 
      // […] 
     } 
    } 
    // […] 
} 

的错误是这样就在这里:

In file included from /homec/hbn28/hbn28e/Sources/qphix/tests/timeDslashNoQDP.cc:6: 
In file included from /homec/hbn28/hbn28e/Sources/qphix/include/qphix/blas.h:8: 
/homec/hbn28/hbn28e/Sources/qphix/include/qphix/blas_c.h:156:54: error: private variable cannot be reduction 
#pragma omp simd aligned(res,x,y:veclen) reduction(+:lnorm) 
                ^
/homec/hbn28/hbn28e/Sources/qphix/include/qphix/blas_c.h:151:12: note: predetermined as private 
           double lnorm=0; 
            ^

由于外omp parallel块,变量lnorm为每个线程定义。然后有一个额外的SIMD部分,每个线程使用一个SIMD通道。减少应该在线程内完成,所以变量的范围看起来是正确的。尽管如此,编译器并不需要它。

这里有什么问题?

的问题似乎是,通过与OpenMP的reduction()条款上它的参数变量规定的要求omp parallel块冲突连接到lnorm变量私人属性(即使lnorm不是私人相对于reduction()子句适用的嵌套omp simd块)。

您可以尝试通过提取lnorm计算代码到它自己的功能,解决该问题:

template <typename FT, int veclen> 
inline double compute_res_and_lnorm(FT *res, 
          FT *x, 
          FT *y, 
          int low, 
          int hi) 
{ 
    double lnorm = 0; 

#pragma omp simd aligned(res, x, y : veclen) reduction(+ : lnorm) 
    for (int i = low; i < hi; i++) { 
     res[i] = x[i] - y[i]; 
     double tmpd = (double)res[i]; 
     lnorm += (tmpd * tmpd); 
    } 
    return lnorm; 
} 

template <typename FT, int veclen> 
inline void xmyNorm2Spinor(FT *res, 
          FT *x, 
          FT *y, 
          double &n2res, 
          int n, 
          int n_cores, 
          int n_simt, 
          int n_blas_simt) { 
#if defined(__GNUG__) && !defined(__INTEL_COMPILER) 
    double norm2res __attribute__((aligned(QPHIX_LLC_CACHE_ALIGN))) = 0; 
#else 
    __declspec(align(QPHIX_LLC_CACHE_ALIGN)) double norm2res = 0; 
#endif 

#pragma omp parallel shared(norm_array) 
    { 
     // […] 
     if (smtid < n_blas_simt) { 
      // […] 
      double lnorm = compute_res_and_lnorm(res, x, y, low, hi); 
      // […] 
     } 
    } 
    // […] 
}