Search code examples
c++gccopenmpsimd

openmp omp declare uniform this not supported in GCC?


I have a simple matrix class which I'd like to vectorize its add operator. However, uniform this seems not to be supported under GCC (works fine using Intel C++ Compiler). I am curios if there is any workaround. (below is the code along compile command)

Please let me know if you have any comments.

#include <iostream>
#include <cassert>
#include <omp.h>


#define printvar(a) std::cerr << (#a) << " = " << (a) << std::endl;
#define printline std::cerr << "FILE " << __FILE__ << " LINE " << __LINE__ << " FUNC: " << __func__ << std::endl;
#define NUMEL 10000

#pragma omp declare simd simdlen(2)
#pragma omp declare simd simdlen(4)
#pragma omp declare simd simdlen(8)
#pragma omp declare simd simdlen(16)
int myadd(int a, int b){
    return a+b;
}

template <typename V>
class Matrix {
public:
    V* data;
    int nrows, ncols;
    bool istemp = false;
    std::string name;
    Matrix(){
        data = NULL;
    }
    Matrix(int nrows, int ncols, V val, std::string name = "none"){

        this->nrows = nrows;
        this->ncols = ncols;
        this->name = name;


        data = (V*) malloc(sizeof(V)*nrows*ncols);
        for(int i = 0; i < numel(); i++){
            csi0(i) = val;
        }

    }

    Matrix(const Matrix& m){

        this->nrows = m.nrows;
        this->ncols = m.ncols;
        this->data = (V*) malloc(sizeof(V)*nrows*ncols);
        for(int i = 0; i < numel(); i++){
            csi0(i) = m.csi0(i);
        }

    }

    inline void swap(Matrix<V>& a, Matrix<V>& b){
        V* data = a.data; a.data = b.data; b.data = data; 
        int nrows = a.nrows; a.nrows = b.nrows; b.nrows = nrows; 
        int ncols = a.ncols; a.ncols = b.ncols; b.ncols = ncols; 
    }

    Matrix<V>& operator=(const Matrix<V>& m){
        Matrix<V> tmp(m);
        swap(*this,tmp);        
    }

    #pragma omp declare simd 
    #pragma omp declare simd simdlen(4) uniform(this)
    #pragma omp declare simd simdlen(8) uniform(this)
    #pragma omp declare simd simdlen(16) uniform(this)
    V& csi0 (int i) const {
        return this->data[i];
    }

    V& cij0 (int i, int j) const {
        return data[i+nrows*j];
    }

    int numel() const {     
        return nrows*ncols;
    }

    friend Matrix<V> operator+(const Matrix<V>& a, const Matrix<V>& b){

        assert(a.nrows == b.nrows && a.ncols == b.ncols);
        Matrix<V> retmat(a.nrows, a.ncols, 0, "retmat");
        #pragma omp parallel for simd 
        for(int i = 0; i < a.numel(); i++){
            retmat.csi0(i) = a.csi0(i) + b.csi0(i);
        }

        // retmat.istemp = true;
        return retmat;
    }

    ~Matrix(){
        if(data != NULL && !istemp){
    
            free(data);
        }

    }


    friend std::ostream& operator<<(std::ostream& os, Matrix<V> m){
        os << "{{" << std::endl;
        for(int i = 0; i < m.nrows; i++){
            for(int j = 0; j < m.ncols; j++){
                os << m.csi0(i) << ", ";
            }
            os << std::endl;
        }
        os << "}}" << std::endl;
        return os;
    }
};

int main(int argc, char const *argv[])
{
    Matrix<int> a(4,5,1), b(4,5,2), c;
    c = a + b;
    printvar(c)
}



int main_1(int argc, char const *argv[])
{
    int a[NUMEL], b[NUMEL], c[NUMEL];

    #pragma omp parallel for 
    for(int i = 0; i < NUMEL; i++){
        c[i] = myadd(a[i], b[i]);
    }
    return 0;
}

Compile command

g++.exe -fopt-info-all=all.optrpt -O3  -fopenmp -fopenmp-simd -mthreads -mavx -fmax-errors=5   -c gcc_ompsimd_test.cpp -Fo:gcc_ompsimd_test.o
gcc_ompsimd_test.cpp:65:46: error: expected unqualified-id before 'this'
  #pragma omp declare simd simdlen(4) uniform(this)
                                              ^~~~
gcc_ompsimd_test.cpp:66:46: error: expected unqualified-id before 'this'
  #pragma omp declare simd simdlen(8) uniform(this)
                                              ^~~~
gcc_ompsimd_test.cpp:67:47: error: expected unqualified-id before 'this'
  #pragma omp declare simd simdlen(16) uniform(this)

Solution

  • It seems that in gcc you cannot use uniform(this) inside class declaration. It is OK in clang and Intel compilers. So, definition of the member function should not be in class declaration:

    #pragma omp declare simd simdlen(16) uniform(this)
    template <typename V>
    V& Matrix<V>::csi0 (int i) const 
    {
        return data[i];
    }
    

    Starting from OpenMP 4.5 the specification contains the following line (2.8.2).

    The special this pointer can be used as if it was one of the arguments to the function in any of the linear, aligned, or uniform clauses.

    So any OpenMP 4.5 compilant compiler should support it.