前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >opencl:C++11下使用别名(x,y,z,hi,lo...)访问vector类型(cl_int2,cl_long16...)的元素

opencl:C++11下使用别名(x,y,z,hi,lo...)访问vector类型(cl_int2,cl_long16...)的元素

作者头像
10km
发布2019-05-25 22:36:27
1K0
发布2019-05-25 22:36:27
举报
文章被收录于专栏:10km的专栏10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433751

在gcc(5.2.0)下使用C++11写opencl的主机端代码时,发现无法像内核代码一样对cl_int2这样的向量(vector)类型用pos.x,pos.y这样的别名来访问向量元素,只能用pos.s[0]这种数组访问的方式。这是为什么?

这本是个小问题,但本人是个完美主义者,总想搞个清楚,最后总算搞清楚了,于是就有了本文。

这是platform.hcl_int2的定义,可以看出,虽然代码中有,x,y名字定义,但编译开关__CL_HAS_ANON_STRUCT__导致这部分代码是灰的/无效的


opencl内核代码中向量元素的访问

在opencl内核代码中,对于opencl中的向量类型,既可以使用s0~sF(根据向量长度不同)来访问向量中的指定元素,也可以用元素的别名来访问(x,y,z,w,hi,lo…)

比如向量数据float4 ,是由4个float组成的向量

float4 f;
float s0=f.s0; //f中第一个元素
float s0=f.x;  //与前一行等价
float2 f2=f.hi //f中前2个元素组成的float2

可以看出,使用x,y,hi,lo这样的别名,代码更加直观易懂。

opencl主机端向量类型的定义

这些向量类型在主机端都有等价的向量类型定义,区别就是类型名字加了cl_前缀,如内核代码中int2类型在主机端是cl_int2,内核代码中float4类型在主机端是cl_float4

参见下面的cl_float4的定义:

typedef union
{
    cl_float  CL_ALIGNED(16) s[4];
#if __CL_HAS_ANON_STRUCT__
   __CL_ANON_STRUCT__ struct{ cl_float   x, y, z, w; };
   __CL_ANON_STRUCT__ struct{ cl_float   s0, s1, s2, s3; };
   __CL_ANON_STRUCT__ struct{ cl_float2  lo, hi; };
#endif
#if defined( __CL_FLOAT2__) 
    __cl_float2     v2[2];
#endif
#if defined( __CL_FLOAT4__) 
    __cl_float4     v4;
#endif
}cl_float4;
// 摘自cl_platform.h

从上面cl_float4的定义可以看出主机端的cl_float4是个联合体,默认是以数字下标访问向量元素的(s0,s1,s2,s3)。同时它也支持以别名(x,y,z,w,s0~s3)访问元素。

编译器差异

不过你也看到了这些别名都定义在匿名结构体(anonymous struct)中,而匿名结构体并不是C语言标准的一部分,是编译器自行实现的,所以__CL_HAS_ANON_STRUCT__宏开关决定编译器是否支持匿名结构体(anonymous struct),控制着是否允许使用别名访问元素。

于是我顺藤摸瓜找到__CL_HAS_ANON_STRUCT__定义的位置,就是下面这段代码(中文部分是作者加的注释)

/* Define capabilities for anonymous struct members. */
#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ )
// gcc下如果没定义__STRICT_ANSI__,则__CL_HAS_ANON_STRUCT__为1
#define  __CL_HAS_ANON_STRUCT__ 1
#define  __CL_ANON_STRUCT__ __extension__
#elif defined( _WIN32) && (_MSC_VER >= 1500)
// VS2008以后支持匿名结构体,但会有警告,所以这里会有关闭C4201警告
   /* Microsoft Developer Studio 2008 supports anonymous structs, but
    * complains by default. */
#define  __CL_HAS_ANON_STRUCT__ 1
#define  __CL_ANON_STRUCT__
   /* Disable warning C4201: nonstandard extension used : nameless
    * struct/union */
#pragma warning( push )
#pragma warning( disable : 4201 )
#else
// gcc下如果定义了__STRICT_ANSI__,则__CL_HAS_ANON_STRUCT__为0
#define  __CL_HAS_ANON_STRUCT__ 0
#define  __CL_ANON_STRUCT__
#endif
// 摘自cl_platform.h

上面这段代码控制了__CL_HAS_ANON_STRUCT__ 的定义,可以看出,在使用gcc编译时,__CL_HAS_ANON_STRUCT__是否为1,取决于是否定义了__STRICT_ANSI__

如果定义了__STRICT_ANSI____CL_HAS_ANON_STRUCT__为0,否则为1。

也就是说,在gcc下编译,如果定义__STRICT_ANSI__就没办法使用别名访问向量元素。

下图就是我在Eclipse+MinGW(5.2.0)环境下打开cl_platform.h看到的__CL_HAS_ANON_STRUCT__ 的定义,说明__STRICT_ANSI__被定义了,

根本原因

那么接下来的问题就是:__STRICT_ANSI__**是个什么鬼?**

关于__STRICT_ANSI__来历,请参见我的上一篇博客《C++11:MinGW当指定-std=c++11选项时 默认定义了__STRICT_ANSI__(其实本文的答案也隐藏在这篇博客里)

从这篇博客的标题就可以得知,如果编译代码时使用了-ansi选项,编译器就会定义__STRICT_ANSI__,我找遍了整个项目代码,确信没有使用过-ansi(太高端我从来不知道这个选项),所以并不是因为我使用了-ansi才造成这个问题,而是因为我使用了-std=c++11选项导致编译器自动定义了__STRICT_ANSI__

解决方案

知道了问题的根本原因,解决问题的办法也就有了。

方案1:

第一个办法就是前述博客中最后提到的办法:在使用-std=c++11选项的同时,加上-U__STRICT_ANSI__选项, 用于去掉__STRICT_ANSI__定义

如果你是用cmake来编译项目代码,可以在CMakeList.txt中加入这样的代码

#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持,并去掉__STRICT_ANSI__定义
if(CMAKE_COMPILER_IS_GNUCXX)
    add_compile_options(-std=c++11)
    message(STATUS "optional:-std=c++11")   
    add_compile_options(-U__STRICT_ANSI__)
    message(STATUS "optional:-U__STRICT_ANSI__")    
endif(CMAKE_COMPILER_IS_GNUCXX)

方案二

修改你的源代码,在#include <CL/cl.hpp>#include <CL/opencl.h>语句之前使用#undef __STRICT_ANSI__删除__STRICT_ANSI__定义

#if defined( __GNUC__) && defined( __STRICT_ANSI__ )
#define __STRICT_ANSI__DEFINED__
//删除__STRICT_ANSI__定义
#undef __STRICT_ANSI__  
#endif
#include <CL/cl.hpp>
#ifdef __STRICT_ANSI__DEFINED__
#undef __STRICT_ANSI__DEFINED__
//恢复__STRICT_ANSI__定义
#define __STRICT_ANSI__
#endif

代码做上述修改后,重新rebuild index,

再打开cl_platform.h看到的__CL_HAS_ANON_STRUCT__ 的定义,说明__STRICT_ANSI__没有被定义,

这时再看cl_int的定义,也正常了

这两种解决方案,你可以根据自己的需要来选择,但第二种方案的没有副作用,不会影响项目中其他部分代码的编译。第一种方案会有潜在的副作用,就是可能会影响项目中与opencl无关的代码的编译。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年04月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • opencl内核代码中向量元素的访问
  • opencl主机端向量类型的定义
  • 编译器差异
  • 根本原因
  • 解决方案
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档