gcc C/C++假设没有指针别名问题

10

最近读到,Fortran在数值计算方面比C/C++更快的主要原因是不存在指针别名。

显然,使用restrict__restrict__关键字可以逐个案例地指示给定内存元素的无指针别名。

ICC编译器显然有一个选项-fno-alias,它允许全局假定不存在别名。GCC上有-fno-strict-aliasing,它仅适用于所有别名情况的子集。

是否存在GCC中的选项或在使用特定优化标志时假定不存在别名的某些情况?


7
关于GCC的“-fno-strict-aliasing”,你理解是相反的。这个选项会让编译器担心可能存在某些别名。默认情况下,它假设这些别名不存在。 - Pascal Cuoq
restrict 关键字有作用的情况实际上非常罕见,而且通常很明显在哪些情况下它是有用的。这份文档非常详细,强调了加载和存储的顺序也很重要。但正如我之前所说,你将使用这种优化的情况相当明显易见。 - Alexandre C.
我认为GCC没有类似于Intel选项-fno-alias的东西(基本上相当于通过restrict注释来注释每个指针)。我真的希望它有。 - Royi
如果无法排除别名,编译器将无法对数组循环进行矢量化。__restrict 经常用于矢量化数组循环。 - A Fog
1个回答

17

GCC有一个选项-fstrict-aliasing,它可以全局启用别名优化,并期望确保没有出现非法别名。我相信此优化在-O2-O3下启用。

C++有明确定义的别名规则,符合标准的代码不会与严格别名冲突。特别地,这意味着您不允许通过指向另一种类型的指针来访问一个变量:

float f;
int * p = reinterpret_cast<int*>(&f);  // uh-oh
*p = 0x3FF00000;                       // breaks strict aliasing

这个规则的一个关键例外是,你始终可以通过char类型的指针访问任何变量。(这对于通过IO操作进行序列化是必要的。)

别名规则无法帮助编译器知道同一类型的任何指针是否别名。考虑以下情况:

void add(float * a, float * b, float * c) { *c = *a + *b; }

编译器无法确定 c 是否指向与 ab 不同的内存空间,因此必须小心处理。我认为这就是使用 restrict 的地方,它承诺 float * restrict c 意味着没有别名与 c 相关。


我认为你的分析是正确的:这正是引入“restrict”关键字的情况。另请参阅http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html以获取更多详细信息,包括如何编写使用“restrict”指针的函数来提示编译器如何安排加载和存储。 - Alexandre C.
1
这个答案非常有教育意义,但并没有回答问题。我很难相信除了在应用程序中手动添加“restrict”之外,没有类似于“-fnoalias”的等效选项。 - Saiph
1
我认为OP所说的是两个不同指针指向同一地址的别名问题,这种情况会防止优化。而GCC标志是关于类型别名,而不是地址别名。除非我读错了文档。 - Royi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接