我正在将一些复杂的工程代码移植到OpenCL,并且遇到了带有双精度的select()三元函数的问题。我现在只是使用标量,所以我可以使用简单的C三元运算符()?:但我计划很快转向矢量类型。
我的问题是选择双打需要(长)类型作为比较,但标量关系函数(例如,isgreater)只返回(int)双精度。这些功能的原型是......
int isgreater (double a, double b);
longn isgreater (doublen a, doublen b);
double select (double a, double b, long cmp);
doublen select (doublen a, doublen b, longn cmp);
只有当我将isgreater()的结果转换为long时才能获得标量代码以标量模式编译/运行,因为select要求元素类型的大小相同。
double hi = ...;
double lo = ...;
double res = select (lo, hi, (long)isgreater(T, T_cutoff));
否则,我收到编译器错误,因为select不明确。规范中关于标量和向量双精度的关系掩码类型似乎存在不匹配。
Q1:这是规范中的疏忽还是实施中的错误?英特尔和AMD OpenCL编译器都无法在CPU上构建,因此我猜测它是前者。
Q2:OpenCL标量关系函数返回0/1,向量关系函数返回0 / -1(即设置所有位)。 (int) - >(long)转换似乎与此要求一致,但不是(int) - >(ulong),对吧? (int) - >(long)转换是否代价高昂?
问题3:当(if)切换到矢量双精度时,编译器是否会抛出不必要的显式转换?我想保留标量和矢量类型,因此我可以针对CUDA GPU和SIMD设备(MIC,CPU)而不必保留两个大量的代码集。
感谢您的任何建议。
答案 0 :(得分:0)
Q1: 我要说的是,没有隐含地将isgreater的结果转换为long是规范中的疏忽。
在单个元素的情况下,select应该像三元运算符一样工作。这也是因为在标量情况下isgreater返回1的原因。基本上isgreater应该像>一样工作当使用标量运算符时。
在向量化的情况下,select会查看MSB,这就是因为isgreater返回-1的原因(所有位1所以MSB自然也是1)。
Q2:Int long转换根本不应该是昂贵的。最多只需要1个额外的指令。
Q3: 它不是。
这个问题令人烦恼地阻止了一个代码从1到n元素进行矢量化,它需要对标量情况进行特殊处理。