首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >告诉C++指针数据是16字节对齐的

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

Stack Overflow用户
提问于 2015-06-17 09:08:43
回答 1查看 2.8K关注 0票数 16

我用静态数组写了一些代码,它可以很好地向量化。

代码语言:javascript
复制
float data[1024] __attribute__((aligned(16)));

我想让数组动态分配。我试着这样做:

代码语言:javascript
复制
float *data = (float*) aligned_alloc(16, size*sizeof(float));

但是编译器(GCC 4.9.2),不再能够向量化代码。我认为这是因为它不知道指针数据是16字节对齐的。我收到的消息如下:

代码语言:javascript
复制
note: Unknown alignment for access: *_43

在使用数据之前,我尝试添加这一行,但似乎没有任何作用:

代码语言:javascript
复制
data = (float*) __builtin_assume_aligned(data, 16);

使用不同的变量和restrict无济于事:

代码语言:javascript
复制
float* __restrict__ align_data = (float*) __builtin_assume_aligned(data,16);

示例:

代码语言:javascript
复制
#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;
}

下面是我是如何编译的:

代码语言:javascript
复制
g++ -o test test.cpp -O3 -march=native -ffast-math -fopt-info-optimized

DYNAMIC设置为0时,它会输出:

代码语言:javascript
复制
test.cpp:46:4: note: loop vectorized

但是当它被设置为1时,它不会输出任何内容。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-18 08:49:04

编译器不会向量化循环,因为它不能确定动态分配的指针不会彼此产生别名。允许向量化您的示例代码的一个简单方法是传递--param vect-max-version-for-alias-checks=1000选项。这将允许编译器发出所有必要的检查,以查看指针是否真的有别名。

另一个允许您的示例代码向量化的简单解决方案是重命名main,正如Marc Glisse在他的评论中所建议的那样。名为main的函数显然禁用了某些优化。另外,GCC 4.9.2可以跟踪this->foo (和其他指针成员)在compute中的使用情况,追溯到它们在Test()中的分配情况。

但是,我假设除了在名为main的函数中使用您的类之外,还有其他东西阻止了您的代码在实际代码中被矢量化。一种更通用的解决方案是使用restrict关键字和aligned属性,这样就可以在不使用别名或对齐检查的情况下对代码进行矢量化。如下所示:

代码语言:javascript
复制
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);
}

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

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30880744

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档