【问题标题】:How to do arithmetic with OpenCL vector types in host-side code?如何在主机端代码中使用 OpenCL 向量类型进行算术运算?
【发布时间】:2012-06-14 07:43:12
【问题描述】:

这是我的代码:

#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)...

【问题讨论】:

    标签: c gcc types opencl


    【解决方案1】:

    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

    【讨论】:

      【解决方案2】:

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

      如果您查看 AMD 工具包中的 &lt;CL/cl_platform.h&gt; 标头,您会看到结构是如何定义的。

       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;
      

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

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

      【讨论】:

      • 你会建议破解#if 子句吗?或者这是一个坏主意?因为很多宿主代码已经使用c99了...
      • 我刚刚发现路过的-std=gnu99解决了这个问题!谢谢!
      • 感谢@TeaOverflow。在将一些 OpenCL 和 C++11 代码从 Windows 移植到 Linux 时,我遇到了同样的问题。打开标志-std=gnu++0x 对我有用。
      • 很好的答案。这也可能在某天与 c11 一起使用:stackoverflow.com/a/10981639/895245
      【解决方案3】:

      OpenCL 程序由两部分组成。

      1. 在主机上运行的程序。这通常是用 C 或 C++ 编写的,但它没有什么特别之处,只是它使用了 OpenCL 规范第 4 和 5 节中描述的 API。
      2. 在 OpenCL 设备(通常是 GPU)上运行的内核。这是用第 6 节中指定的语言编写的。这不是 C,但它很接近。它添加了诸如矢量操作之类的东西(就像您尝试使用的那样)。这是由主机程序编译的,通过 API 将包含内核代码的字符串传递给 OpenCL。

      你混淆了两者,并试图在宿主代码中使用内核语言的特性。

      【讨论】:

      • 谢谢!那么floatnand 等的运算符只在内核内部定义?你知道我对-std=c99 的问题来自哪里吗?
      猜你喜欢
      • 2018-12-17
      • 2020-10-11
      • 1970-01-01
      • 2023-03-29
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      相关资源
      最近更新 更多