告诉C++指针数据是16字节对齐的

Azm*_*sov 16 c++ gcc sse memory-alignment

我用静态数组编写了一些代码,它的矢量化很好.

float data[1024] __attribute__((aligned(16)));
Run Code Online (Sandbox Code Playgroud)

我想动态分配数组.我尝试过这样的事情:

float *data = (float*) aligned_alloc(16, size*sizeof(float));
Run Code Online (Sandbox Code Playgroud)

但是编译器(GCC 4.9.2)不再能够对代码进行矢量化.我假设这是因为它不知道指针数据是16字节对齐的.我得到的消息如下:

note: Unknown alignment for access: *_43
Run Code Online (Sandbox Code Playgroud)

我尝试在使用数据之前添加此行,但它似乎没有做任何事情:

data = (float*) __builtin_assume_aligned(data, 16);
Run Code Online (Sandbox Code Playgroud)

使用不同的变量并restrict没有帮助:

float* __restrict__ align_data = (float*) __builtin_assume_aligned(data,16);
Run Code Online (Sandbox Code Playgroud)

例:

#include <iostream>
#include <stdlib.h>
#include <math.h>

#define SIZE 1024
#define DYNAMIC 0
#define A16 __attribute__((aligned(16)))
#define DA16 (float*) aligned_alloc(16, size*sizeof(float))

class Test{
public:
    int size;
#if DYNAMIC
    float *pos;
    float *vel;
    float *alpha;
    float *k_inv;
    float *osc_sin;
    float *osc_cos;
    float *dosc1;
    float *dosc2;
#else
    float pos[SIZE] A16;
    float vel[SIZE] A16;
    float alpha[SIZE] A16;
    float k_inv[SIZE] A16;
    float osc_sin[SIZE] A16;
    float osc_cos[SIZE] A16;
    float dosc1[SIZE] A16;
    float dosc2[SIZE] A16;
#endif
    Test(int arr_size){
        size = arr_size;
#if DYNAMIC
        pos = DA16;
        vel = DA16;
        alpha = DA16;
        k_inv = DA16;
        osc_sin = DA16;
        osc_cos = DA16;
        dosc1 = DA16;
        dosc2 = DA16;
#endif
    }
    void compute(){
        for (int i=0; i<size; i++){
            float lambda = .67891*k_inv[i],
                omega = (.89 - 2*alpha[i]*lambda)*k_inv[i],
                diff2 = pos[i] - omega,
                diff1 = vel[i] - lambda + alpha[i]*diff2;
            pos[i] = osc_sin[i]*diff1 + osc_cos[i]*diff2 + lambda*.008 + omega;
            vel[i] = dosc1[i]*diff1 - dosc2[i]*diff2 + lambda;
        }
    }
};

int main(int argc, char** argv){
    Test t(SIZE);
    t.compute();
    std::cout << t.pos[10] << std::endl;
    std::cout << t.vel[10] << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这是我编译的方式:

g++ -o test test.cpp -O3 -march=native -ffast-math -fopt-info-optimized
Run Code Online (Sandbox Code Playgroud)

DYNAMIC被设定为0,其输出:

test.cpp:46:4: note: loop vectorized
Run Code Online (Sandbox Code Playgroud)

但是当它设置为1它输出什么.

Ros*_*dge 6

编译器没有对循环进行向量化,因为它无法确定动态分配的指针不会相互别名.允许对示例代码进行矢量化的一种简单方法是传递--param vect-max-version-for-alias-checks=1000选项.这将允许编译器发出所有必要的检查,以查看指针是否实际是别名.

另一个允许你的示例代码被矢量化的简单解决方案是重命名main,正如Marc Glisse在他的评论中所建议的那样.名为的函数main显然已禁用某些优化.命名为其他东西,GCC 4.9.2可以跟踪this->foo(以及其他指针成员)在compute其分配中的使用Test().

但是,我假设在一个名为函数的类中使用了一些东西,这会main阻止你的代码在真实代码中被矢量化.允许代码在没有别名或对齐检查的情况下进行矢量化的更通用的解决方案是使用restrict关键字和aligned属性.像这样的东西:

typedef float __attribute__((aligned(16))) float_a16;

__attribute__((noinline))
static void _compute(float_a16 * __restrict__ pos,
         float_a16 * __restrict__ vel,
         float_a16 * __restrict__ alpha,
         float_a16 * __restrict__ k_inv,
         float_a16 * __restrict__ osc_sin,
         float_a16 * __restrict__ osc_cos,
         float_a16 * __restrict__ dosc1,
         float_a16 * __restrict__ dosc2,
         int size) {
    for (int i=0; i<size; i++){
        float lambda = .67891*k_inv[i],
            omega = (.89 - 2*alpha[i]*lambda)*k_inv[i],
            diff2 = pos[i] - omega,
            diff1 = vel[i] - lambda + alpha[i]*diff2;
        pos[i] = osc_sin[i]*diff1 + osc_cos[i]*diff2 + lambda*.008 + omega;
        vel[i] = dosc1[i]*diff1 - dosc2[i]*diff2 + lambda;
    }
}

void compute() {
    _compute(pos, vel, alpha, k_inv, osc_sin, osc_cos, dosc1, dosc2,
         size);
}
Run Code Online (Sandbox Code Playgroud)

noinline属性很关键,否则内联会导致指针失去其限制和对齐性.编译器似乎忽略了restrict函数参数以外的上下文中的关键字.