如何使用OpenCL主机矢量类型进行算术运算?

时间:2012-06-11 11:48:27

标签: c gcc types opencl

继承我的代码:

#include <stdio.h>
#include <CL/cl.h>
#include <CL/cl_platform.h>

int main(){    
    cl_float3 f3 =  (cl_float3){1, 1, 1};
    cl_float3 f31 = (cl_float3) {2, 2, 2};
    cl_float3 f32 = (cl_float3) {2, 2, 2};
    f3 = f31 + f32;
    printf("%g %g %g \n", f3.x, f3.y, f3.z);
    return  0;
}

使用gcc 4.6进行编译时,会产生错误

test.c:14:11: error: invalid operands to binary + (have ‘cl_float3’ and ‘cl_float3’)

对我来说很奇怪,因为OpenCL Specification在第6.4节中除了这个,增加了两个floatn。我是否需要包含任何其他标题?

但更奇怪的是,在使用-std=c99进行编译时,我会收到类似

的错误
test.c:16:26: error: ‘cl_float3’ has no member named ‘x’

..适用于所有组件(x,y和z)......

3 个答案:

答案 0 :(得分:6)

结构下标编译问题的原因可以在AMD SDK中的标准实现中看到。

如果查看AMD工具包中的<CL/cl_platform.h>标题,您可以看到如何定义结构。

 typedef  cl_float4  cl_float3;

 typedef union
 {
    cl_float  CL_ALIGNED(16) s[4];
 #if (defined( __GNUC__) ||  defined( __IBMC__ )) && ! defined( __STRICT_ANSI__ )
   __extension__ struct{ cl_float   x, y, z, w; };
 ....
 #endif
 }cl_float4;

使用#if调用gcc时,将忽略--std=c99子句。

要使代码与--std = c99一起使用,您可以将f3.x的引用替换为f3.s[0],依此类推。

答案 1 :(得分:5)

OpenCL程序由两部分组成。

  1. 在主机上运行的程序。这通常用C或C ++编写,但除了使用第4节和第4节中描述的API之外没有什么特别之处。 5 OpenCL规范。
  2. 在OpenCL设备(通常是GPU)上运行的内核。这是用第6节中指定的语言编写的。这不是C,但它很接近。它增加了矢量操作之类的东西(就像你正在尝试使用的那样)。这是由主程序通过API将包含内核代码的字符串传递给OpenCL来编译的。
  3. 你们对这两者感到困惑,并试图在主机代码中使用内核语言的功能。

答案 2 :(得分:2)

cl_float.v 是另一种选择:

#include <assert.h>
#include <CL/cl.h>

int main(void) {
    cl_float4 f = {{1, 2, 3, 4}};
    cl_float4 g = {{5, 6, 7, 8}};
    cl_float4 h;
    h.v4 = f.v4 + g.v4;
    assert(h.s[0] == 6);
    assert(h.s[1] == 8);
    return EXIT_SUCCESS;
}

可以运行:

gcc -std=c89 -Wall -Wextra tmp.c -lOpenCL && ./a.out 

在Ubuntu 16.10,gcc 6.2.0。

v在Linux GCC x86中通过GCC vector extensions定义。

文件https://github.com/KhronosGroup/OpenCL-Headers/blob/bf0f43b76f4556c3d5717f8ba8a01216b27f4af7/cl_platform.h包含:

#if defined( __SSE__ )
    [...]
    #if defined( __GNUC__ )
        typedef float __cl_float4   __attribute__((vector_size(16)));
    [...]
    #define __CL_FLOAT4__   1

然后:

typedef union
{
[...]
#if defined( __CL_FLOAT4__) 
    __cl_float4     v4;
#endif
}cl_float4;

不确定这种ifdefs的弹幕是Khronos的一个好举动,但它就是我们所拥有的。

我建议您始终使用.s[0],这是最便携的选项。如果我们专注于GPU,我们不应该加速主机SIMD ......

C11匿名结构

错误error: ‘cl_float3’ has no member named ‘x’因为https://stackoverflow.com/a/10981639/895245

中提到的行而发生

更确切地说,此功能称为"anonymous struct",它是在C11中标准化的扩展。

因此理论上它也应该与-std=c11一起使用,但它目前还没有,因为CL标题没有更新以检查C11,另请参阅:https://github.com/KhronosGroup/OpenCL-Headers/issues/18