C代码自动向量化浮点最小值

时间:2013-08-16 02:58:11

标签: c gcc vectorization sse simd

我在我的内部循环中有一些代码,我正在使用它来为我正在编写的光栅化算法钳制一些错误值:

float cerror[4] = {
    MINF(error[0], 1.0f), 
    MINF(error[1], 1.0f), 
    MINF(error[2], 1.0f), 
    MINF(error[3], 1.0f) 
}; 

其中MINF只是MINF(a,b)=((a)<(b))? (a):( b)

事实证明我有4个错误值我必须在这个内部循环中更新所有浮点数,所以如果我可以将它们全部存储在SSE寄存器中并且使用minps计算最小值而不是单独,但编译器似乎并没有为我做这件事。

我甚至尝试将它移动到它自己的功能,所以我可以看到矢量化器输出:

void fclamp4(float* __restrict__ aa, float* __restrict__ bb) {
    for (size_t ii=0; ii < 4; ii++) {
        aa[ii] = (bb[ii] > 1.0) ? 1.0f : bb[ii];
    }
}

这给了我类似的东西:

  

inc / simplex.h:1508:注意:没有矢量化:不支持的数据类型bool
  inc / simplex.h:1507:注意:函数中的向量化0循环。

有没有办法更好地鼓励编译器为我这样做?如果我可以避免它,我宁愿不直接跳到教义,所以代码仍然是可移植的。是否有共同模式的一般参考?

最后,我的所有错误/错误/错误增量都存储在堆栈上的float [4]数组中,我是否需要手动对齐这些?或者编译器可以为我处理这些吗?

编辑:使用对齐类型进行游戏但仍然没有骰子。

#include <stdio.h>                                                                                                                                                                                              
#include <stdlib.h>                                                                                                                                                                                             

typedef float __attribute__((aligned (16))) float4[4];                                                                                                                                                          

inline void doit(const float4 a, const float4 b, float4 c) {                                                                                                                                                    
    for (size_t ii=0; ii < 4; ii++) {                                                                                                                                                                           
        c[ii] = (a[ii] < b[ii]) ? a[ii] : b[ii];                                                                                                                                                                
    }                                                                                                                                                                                                           
}                                                                                                                                                                                                               

int main() {                                                                                                                                                                                                    
    float4 a = {rand(), rand(), rand(), rand() };                                                                                                                                                               
    float4 b = {1.0f,   1.0f,   1.0f,   1.0f   };                                                                                                                                                               
    float4 c;                                                                                                                                                                                                   

    doit((float*)&a, (float*)&b, (float*)&c);                                                                                                                                                                   

    printf("%f\n", c[0]);                                                                                                                                                                                       
}                                                                                                                                                                                                               

矢量化器说:

  

ssetest.c:7:注意:vect_model_load_cost:已对齐。
  ssetest.c:7:注意:vect_model_load_cost:inside_cost = 4,outside_cost = 0。
  ssetest.c:7:注意:vect_model_load_cost:对齐。
  ssetest.c:7:注意:vect_model_load_cost:inside_cost = 4,outside_cost = 0。
  ssetest.c:7:注意:未向量化:不支持相关的stmt:D.3177D.3177_22 = iftmp.4_18&lt; iftmp.4_21;

     

ssetest.c:12:注意:函数中的向量化0循环。

再次编辑:我应该注意到我一直在GCC 4.4.7(RHEL 6)和GCC 4.6(Ubuntu)上尝试这个,两者都没有运气。

2 个答案:

答案 0 :(得分:1)

看起来在GCC中,除非指定-ffast-math或-fassociative-math,否则不会启用缩减的矢量化。当我启用那些它矢量化就好了(在内循环中使用fminf):

  

ssetest.c:9:注意:vect_model_load_cost:已对齐。
  ssetest.c:9:注意:vect_model_load_cost:inside_cost = 1,outside_cost = 0。
  ssetest.c:9:注意:vect_model_load_cost:对齐。
  ssetest.c:9:注意:vect_model_load_cost:inside_cost = 1,outside_cost = 0。
  ssetest.c:9:注意:vect_model_simple_cost:inside_cost = 1,outside_cost = 0。
  ssetest.c:9:注意:vect_model_store_cost:inside_cost = 1,outside_cost = 0。
  ssetest.c:9:注意:成本模型分析:
   循环成本内的矢量:4
   循环成本之外的向量:0
   标量迭代成本:4
   标量外部费用:0
   序言迭代:0
   结语迭代:0
   计算出盈利能力的最低标准:1

     

ssetest.c:9:注意:获利能力阈值= 3

     

ssetest.c:9:注意:LOOP VECTORIZED   ssetest.c:15:注意:在函数中向量化了1个循环。

答案 1 :(得分:0)

fminf涉及对非有限操作数的处理的特殊要求,当设置-ffinite-math-only时,gcc可以忽略这些要求(如-ffast-math那样)。