【问题标题】:C code to auto-vectorize floating point minimum自动矢量化浮点最小值的 C 代码
【发布时间】:2013-08-18 09:03:57
【问题描述】:

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

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)

事实证明我有 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 循环。

有没有办法更好地鼓励编译器为我这样做?如果我可以避免它,我宁愿不直接跳到内在,这样代码就可以保持可移植性。是否有通用模式的一般参考?

最后,我所有的 error/cerror/error 增量都存储在堆栈上的 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

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

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

【问题讨论】:

    标签: c gcc vectorization sse simd


    【解决方案1】:

    除非您指定 -ffast-math 或 -fassociative-math,否则在 GCC 中似乎未启用缩减向量化。当我启用它们时,它可以很好地矢量化(在内部循环中使用 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:注意:循环矢量化。
    ssetest.c:15:注意:函数中的向量化 1 循环。

    【讨论】:

    • 这对我来说似乎也很奇怪,但我相信 GCC 认为 min 操作是一个归约运算符,如果没有这两个选项之一,它不会对归约进行矢量化,这很糟糕。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2010-09-29
      • 1970-01-01
      • 2022-11-16
      • 2013-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-11
      相关资源
      最近更新 更多