2012-04-03 4 views
1

Ich versuche, Code zu schreiben, um ein Array eines nativen C++ - Typs in einen Vektor mit geeigneter Größe zu konvertieren, der vom OpenCL-Standard definiert wird.Wie kann ein Klassenmembertyp, der von Vorlagenparametern abhängt, besser behandelt werden?

Endian-Ness und Packing sind OpenCL-spezifische Implementierung. Die OpenCL-Typen bieten keinen praktischen Operator []. (eigentlich ist die API C) Ein weiteres Problem: cl_int4 hat eine .s3 Mitglied, aber cl_int2 nicht.

Ich habe etwas, das funktionell funktioniert, aber Sie können sehen, dass ich in das Land der Schablone verrückt gegangen bin.

Kann dies besser gemacht werden? Diese Funktionen werden nicht oft aufgerufen, daher wäre besser eine Kombination aus reduzierter Programmbinärgröße und weniger langem Quellcode.

Hier ist, was ich bisher habe. Ich zeige Ihnen nicht alle dimensionalen Spezialisierungen (3-6 weglassen), und ich möchte auch für mindestens den Integer-Typ auch implementieren.

#include <CL/cl.h> 

template < typename HOST_T, int NUM_DIM > 
struct Payload_t; 

// Vector length needs to be (for dims 1-6): 2, 4, 8, 8, 16, 16 

//single precision 

template < > 
struct __attribute__((packed)) Payload_t <float, 1> { 
    cl_float2 vec; 
    void setElement(int pos, float value) 
    { 
     switch (pos) { 
      case 0: vec.s0 = value; return; 
      case 1: vec.s1 = value; return; 
      default: return; 
     } 
    } 
}; 

template < > 
struct __attribute__((packed)) Payload_t <float, 2> { 
    cl_float4 vec; 
    void setElement(int pos, float value) 
    { 
     switch (pos) { 
      case 0: vec.s0 = value; return; 
      case 1: vec.s1 = value; return; 
      case 2: vec.s2 = value; return; 
      case 3: vec.s3 = value; return; 
      default: return; 
     } 
    } 
}; 

/// double-precision 

template < > 
struct __attribute__((packed)) Payload_t <double, 1> { 
    cl_double2 vec; 
    void setElement(int pos, double value) 
    { 
     switch (pos) { 
      case 0: vec.s0 = value; return; 
      case 1: vec.s1 = value; return; 
      default: return; 
     } 
    } 
}; 

template < > 
struct __attribute__((packed)) Payload_t <double, 2> { 
    cl_double4 vec; 
    void setElement(int pos, double value) 
    { 
     switch (pos) { 
      case 0: vec.s0 = value; return; 
      case 1: vec.s1 = value; return; 
      case 2: vec.s2 = value; return; 
      case 3: vec.s3 = value; return; 
      default: return; 
     } 
    } 
}; 

Ich denke, Sie könnten neugierig sein, wie ich diese Klasse verwenden würde. In einem Beispiel habe ich eine Klasse, die auf den Typ REAL templatiert ist und eine Instanz der folgenden Mitgliedsklasse hat, in der eine Instanz der Payload_t enthalten ist.

template <int NUM_DIM > 
struct cartesian_box_descriptor_t : cartesian_box_descriptor_base_t 
{ 
    static const int vectorLengthArray[6]; 
    void set_dx(REAL * dx_vec) 
    { 
     for (int i = 0; i < NUM_DIM; ++i) 
      payload.setElement(i, dx_vec[i]); 
    }; 
    void set_startx(REAL * startx_vec) 
    { 
     for (int i = 0; i < NUM_DIM; ++i) 
      payload.setElement(NUM_DIM + i , startx_vec[i]); 
    }; 

    virtual WxAny getDescriptorStruct() const 
    { 
     return WxAny(payload); // packages this simple structure as 'scalar' with hidden type 
    }; 


    Payload_t< REAL, NUM_DIM> payload; 
}; 

getDescriptorStruct() Die Pakete der OpenCL unterstützten Typ in einer Weise, die ich zur OpenCL API als Kernel-Argument mit allen Bytes fallen an der richtigen Stelle senden.

Wenn jemand über einen Paradigmenwechsel nachdenkt, muss ich immer nur den gesamten Vektor auf einmal einstellen.

+0

Link zur OpenCL-Vektortypspezifikation. http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/vectorDataTypes.html – NoahR

Antwort

0

Ich bin mir nicht sicher, ob ich stolz sein oder mich dafür schämen sollte, aber es funktioniert. Sie müssen sicherstellen, dass alle Aufrufe von set() genau die richtigen Typen verwenden. Es behandelt neue cl_ types automatisch und neue Größen von cl_ types mit Änderungen an nur 3 Stellen. Es könnte wahrscheinlich noch weiter aufgeräumt werden, wenn sich jemand so geneigt fühlt.

#include<iostream> 
#include<assert.h> 

struct cl_float1 { 
    float s0; 
}; 

struct cl_float2 { 
    float s0; 
    float s1; 
}; 


#define ZERO_THROUGH_15(pre) \ 
    pre i0;   \ 
    pre i1;   \ 
    pre i2;   \ 
    pre i3;   \ 
    pre i4;   \ 
    pre i5;   \ 
    pre i6;   \ 
    pre i7;   \ 
    pre i8;   \ 
    pre i9;   \ 
    pre i10;   \ 
    pre i11;   \ 
    pre i12;   \ 
    pre i13;   \ 
    pre i14;   \ 
    pre i15 


template<typename SIMD, typename POD> 
struct offset { 
    static POD SIMD::* data[16]; 
    ZERO_THROUGH_15(static bool); 
    offset() { 
    ZERO_THROUGH_15(); 
    } 
}; 
template<typename SIMD, typename POD> 
/*static*/ POD SIMD::* offset<SIMD,POD>::data[16]; 

template<int n> 
struct offsetGetter { 
    template<typename SIMD, typename POD> 
    static POD SIMD::* get(...) { 
    return NULL; 
    } 
}; 

#define GET_OFFSET(n) \ 
template<> \ 
struct offsetGetter<n> { \ 
    template<typename SIMD, typename POD, POD SIMD::* OFS> \ 
    struct check {}; \ 
\ 
    template<typename SIMD, typename POD> \ 
    static POD SIMD::* get(check<SIMD, POD, &SIMD::s ## n>*) { \ 
    return &SIMD::s ## n; \ 
    } \ 
\ 
    template<typename SIMD, typename POD> \ 
    static POD SIMD::* get(...) { \ 
    return NULL; \ 
    } \ 
    template<typename SIMD, typename POD> \ 
    static bool init() { \ 
    offset<SIMD,POD>::data[n] = get<SIMD,POD>(NULL); \ 
    }; \ 
}; \ 
template<typename SIMD, typename POD> \ 
/*static*/ bool offset<SIMD,POD>::i##n = offsetGetter<n>::init<SIMD,POD>() 

GET_OFFSET(0); 
GET_OFFSET(1); 
GET_OFFSET(2); 
GET_OFFSET(3); 
GET_OFFSET(4); 
GET_OFFSET(5); 
GET_OFFSET(6); 
GET_OFFSET(7); 
GET_OFFSET(8); 
GET_OFFSET(9); 
GET_OFFSET(10); 
GET_OFFSET(11); 
GET_OFFSET(12); 
GET_OFFSET(13); 
GET_OFFSET(14); 
GET_OFFSET(15); 

template<typename SIMD, typename POD> 
void set(SIMD& simd, int n, POD val) { 
    offset<SIMD,POD> ignoreme; 
    POD SIMD::* ofs = offset<SIMD,POD>::data[n]; 
    assert(ofs); 
    simd.*ofs = val; 
} 

main(){ 
    cl_float2 x; 
    set(x, 0, 42.0f); 
    std::cout << x.s0 << std::endl; // prints 42 
    set(x, 1, 52.0f); 
    std::cout << x.s1 << std::endl; // prints 52 
    cl_float1 y; 
    set(y, 1, 42.0f); // assertion failure 
} 
+0

Wow. Ich habe versucht, mich durch diesen Weg zu waten. Ein paar Notizen für jetzt. cl_float1 ist kein OpenCL-Typ, sondern cl_float. Ich ersetzte die beiden Strukturdefinitionen mit dem OpenCL-Header wie in meinem Beispielcode. Mit diesen Änderungen erhalte ich einen Assertionsfehler von der Zeile 'assert (ofs)', sogar vor jeder Zeile 'set()' in 'main()'. Ich bekomme auch 80 Warnungen, ich denke, dass alle im Zusammenhang mit der 'static bool init()' -Funktion nicht zurückkommen. Können Sie diese beiden Fragen kommentieren? – NoahR