Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何告诉GCC指针参数始终是双字对齐的?_C_Gcc_Alignment_C99 - Fatal编程技术网

如何告诉GCC指针参数始终是双字对齐的?

如何告诉GCC指针参数始终是双字对齐的?,c,gcc,alignment,c99,C,Gcc,Alignment,C99,在我的程序中,我有一个简单的向量加法函数c[0:15]=a[0:15]+b[0:15]。功能原型为: void vecadd(float * restrict a, float * restrict b, float * restrict c); 在我们的32位嵌入式体系结构上,有一个加载/存储选项,可以加载/存储双字,如: r16 = 0x4000 ; strd r0,[r16] ; stores r0 in [0x4000] and r1 in [0x4004] GCC优化器识别循环的

在我的程序中,我有一个简单的向量加法函数
c[0:15]=a[0:15]+b[0:15]
。功能原型为:

void vecadd(float * restrict a, float * restrict b, float * restrict c);
在我们的32位嵌入式体系结构上,有一个加载/存储选项,可以加载/存储双字,如:

r16 = 0x4000  ;
strd r0,[r16] ; stores r0 in [0x4000] and r1 in [0x4004]
GCC优化器识别循环的向量性质并生成两个代码分支——一个用于3个数组双字对齐的情况(因此它使用双加载/存储指令),另一个用于数组字对齐的情况(使用单加载/存储选项)

问题是相对于加法部分,地址对齐检查的成本很高,我想通过提示编译器a、b和c始终是8对齐的来消除它。是否有要添加到指针声明中的修饰符来告诉编译器这一点


用于调用此函数的数组具有aligned(8)属性,但它不会反映在函数代码本身中。是否可以将此属性添加到函数参数中?

我从未使用过它,但有\u属性((对齐(8))

如果我正确阅读了文档,那么它的使用方式如下:

void vecadd(float * restrict a __attribute__((aligned (8))), 
            float * restrict b __attribute__((aligned (8))), 
            float * restrict c __attribute__((aligned (8))));

请参见对齐规范通常仅适用于小于指针基本类型的对齐,而不适用于较大的对齐

我认为最简单的方法是用对齐规范声明整个数组,比如

typedef float myvector[16];
typedef myvector alignedVector __attribute__((aligned (8));
(语法可能不正确,我总是很难知道将这些
\uuuu属性\uuuu
放在哪里)

并在整个代码中使用该类型。对于你的函数定义,我会试试

void vecadd(alignedVector * restrict a, alignedVector * restrict b, alignedVector * restrict c);

这提供了一个额外的间接寻址,但这只是语法。类似于
*a
的东西只是一个noop,只会将指针重新解释为指向第一个元素的指针。

gcc版本在简单的typedef和数组上的align()问题上一直很狡猾。通常,要执行所需操作,必须将浮点封装在结构中,并使包含的浮点具有对齐限制

使用运算符重载,几乎可以使这个无痛,但它确实假设您可以使用C++语法。< /P>

#include <stdio.h>
#include <string.h>

#define restrict __restrict__

typedef float oldfloat8 __attribute__ ((aligned(8)));

struct float8
{
    float f __attribute__ ((aligned(8)));

    float8 &operator=(float _f) { f = _f; return *this; }
    float8 &operator=(double _f) { f = _f; return *this; }
    float8 &operator=(int _f) { f = _f; return *this; }

    operator float() { return f; }
};

int Myfunc(float8 * restrict a, float8 * restrict b, float8 * restrict c);

int MyFunc(float8 * restrict a, float8 * restrict b, float8 * restrict c)
{
    return *c = *a* *b;
}

int main(int argc, char **argv)
{
    float8 a, b, c;

    float8 p[4];

    printf("sizeof(oldfloat8) == %d\n", (int)sizeof(oldfloat8));
    printf("sizeof(float8) == %d\n", (int)sizeof(float8));

    printf("addr p[0] == %p\n", &p[0] );
    printf("addr p[1] == %p\n", &p[1] );

    a = 2.0;
    b = 7.0;
    MyFunc( &a, &b, &c );
    return 0;
}
#包括
#包括
#定义限制\uu限制__
typedef float oldfloat8_uuu属性_uuu((对齐(8)));
结构浮动8
{
浮动f_uuu属性_uuu((对齐(8));
float8&运算符=(float{f=\f;返回*this;}
float8&运算符=(double _f){f=_f;返回*this;}
float8&运算符=(int _f){f=_f;返回*this;}
运算符float(){return f;}
};
int Myfunc(float8*限制a、float8*限制b、float8*限制c);
int MyFunc(float8*限制a、float8*限制b、float8*限制c)
{
返回*c=*a**b;
}
int main(int argc,字符**argv)
{
8 a,b,c;
8 p[4];
printf(“sizeof(oldfloat8)=%d\n”,(int)sizeof(oldfloat8));
printf(“sizeof(float8)=%d\n”,(int)sizeof(float8));
printf(“addr p[0]=%p\n”、&p[0]);
printf(“addr p[1]=%p\n”、&p[1]);
a=2.0;
b=7.0;
MyFunc(a&b&c);
返回0;
}

如果属性不起作用,或者不是选项

我不确定,但试试这个:

void vecadd (float * restrict a, float * restrict b, float * restrict c)
{
   a = __builtin_assume_aligned (a, 8);
   b = __builtin_assume_aligned (b, 8);
   c = __builtin_assume_aligned (c, 8);

   for ....
这应该告诉GCC指针是对齐的。从这一点来看,它是否能满足您的需要取决于编译器是否能有效地使用这些信息;这可能不够聪明:这些优化并不容易

另一个选项可能是将浮点封装在必须对齐8字节的联合中:

typedef union {
  float f;
  long long dummy;
} aligned_float;

void vedadd (aligned_float * a, ......

我认为这应该强制执行8字节对齐,但同样,我不知道编译器是否足够聪明来使用它。

根据我在系统上找到的一段示例代码,我尝试了以下解决方案,其中包含了前面给出的一些答案的思想:基本上,创建具有64位类型的小型浮点数组的并集(在本例中为浮点的SIMD向量),并使用操作数浮点数组的强制转换调用函数:

typedef float f2 __attribute__((vector_size(8)));
typedef union { f2 v; float f[2]; } simdfu;

void vecadd(f2 * restrict a, f2 * restrict b, f2 * restrict c);

float a[16] __attribute__((aligned(8)));
float b[16] __attribute__((aligned(8)));
float c[16] __attribute__((aligned(8)));

int main()
{
    vecadd((f2 *) a, (f2 *) b, (f2 *) c);
    return 0;
}
现在编译器不会生成4对齐的分支

然而,
\uuuuuuuuuuuuuuu-inspect\u aligned()
将是更好的解决方案,如果它只起作用的话,可以防止石膏和可能的副作用

编辑:我注意到,在我们的实现中,内置函数实际上是有缺陷的(即,它不仅不工作,而且会在代码的后面导致计算错误)

如何告诉GCC指针参数始终是双字对齐的

新版本的GCC似乎有:

内置函数:
void*\uu内置假定\u对齐(const void*exp,size\u t align,…)

此函数返回其第一个参数,并允许编译器假定返回的指针至少对齐字节。 这个内置函数可以有两个或三个参数,如果有三个, 第三个参数应为整数类型,如果为非零 表示未对准偏移。例如:

void *x = __builtin_assume_aligned (arg, 16);
意味着编译器可以假设x(设置为arg)至少是16字节对齐的,而:

void *x = __builtin_assume_aligned (arg, 32, 8);
这意味着编译器可以为x假设(char*)x-8是32字节对齐的,设置为arg


根据2010年前后关于堆栈溢出的一些其他问题和答案,GCC 3和早期GCC 4中似乎没有内置的。但我不知道截止点在哪里。

除非我错过了它,否则GCC文档和您链接到的页面中提到了变量和函数的align属性,而不是函数原型的align属性e参数。你能指出你链接到的页面中的相关部分吗?我认为这不会起作用。这会告诉编译器指针变量本身是8字节对齐的。我可以确认这不会编译。
错误:可能没有为
指定对齐。我想参数的typedef会清除编译错误。e即使我下面的代码无法帮助您(因为它是C++),您也可能希望打印F(“%p”)&数组[0]a