C++ 是否可以启用链接时间优化,同时仅禁用某些函数的严格别名?
我的程序遵循严格的别名规则,除了一个地方:一个编译单元,它包含杂凑函数,如MurruldHash3、SpookyHash等。在x86和x86_64上,这些杂凑函数接受一个C++ 是否可以启用链接时间优化,同时仅禁用某些函数的严格别名?,c++,c,strict-aliasing,C++,C,Strict Aliasing,我的程序遵循严格的别名规则,除了一个地方:一个编译单元,它包含杂凑函数,如MurruldHash3、SpookyHash等。在x86和x86_64上,这些杂凑函数接受一个const char*,将它们强制转换为uint32,并以4字节的块处理数据。这使得它们比逐字节处理数据快得多,但我相信这打破了严格的别名规则。现在,我用-fno严格别名编译这个编译单元,而用-fstrict别名编译程序的其余部分 但我想知道如果启用链接时间优化会发生什么。据我所知,GCC和Clang通过将程序源代码存储到.o文
const char*
,将它们强制转换为uint32
,并以4字节的块处理数据。这使得它们比逐字节处理数据快得多,但我相信这打破了严格的别名规则。现在,我用-fno严格别名编译这个编译单元,而用-fstrict别名编译程序的其余部分
但我想知道如果启用链接时间优化会发生什么。据我所知,GCC和Clang通过将程序源代码存储到.o文件中来实现链接时间优化,以便在链接阶段编译器知道整个程序的源代码。那么,是否仍然可以仅对哈希函数禁用严格别名?还是现在必须禁用整个程序的严格别名?或者我完全误解了事情的意思,而事实上MurruseHash3/SpookyHash是严格遵守别名的吗?这应该是可能的(至少您可以尝试),因为最近的GCC提供了。您可以尝试添加以下内容
#pragma GCC optimize ("-fstrict-aliasing")
在您的别名函数之前,将
#pragma GCC reset_options
在他们后面
也许你需要把这些包起来
#if __GNUC__ >= 4
当然还有一些#endif
或者,使用生成器技巧(例如,autoconf
,cmake
,或复杂的GNU make 4.0规则等)将您自己的HAVE_-general\u-GCC
定义为1(仅适用于正版编译器),将您自己的HAVE_-general\u-CLANG
定义为1(适用于正版编译器),等等。。。。或者可能检测到在某些示例代码中理解了上述杂注,然后将HAVE\u WORKING\u PRAGMA\u GCC\u OPTIMIZE
定义为1
顺便说一句,至少在GCC上,-flto
并没有在目标文件中存储程序源的表示形式,而只是编译源代码时获得的一些GCC内部表示形式(如Gimple等)的摘要形式。这是完全不同的
注:我没有试过,所以可能没那么简单。有三件事需要考虑:
- 演出
- 便携性
- 标准符合性
-fno严格的别名
-这正是单元测试非常方便的地方
对于SpookyHash,我实际上有(它还修复了参考实现V2中的off by 1)。如果您不介意违反有效类型,并且您的体系结构支持未对齐的访问(或者所有输入数据都对齐),则可以传递-DSPOOKY\u NOCOPY
编译器标志。在我的x86-64机器上,根据输入大小,性能提高约10-20%
现在,我用-fno严格别名编译这个编译单元,而用-fstrict别名编译程序的其余部分
对于链接时间优化,您也可以这样做。只是不要使用链接时优化编译特定的目标代码
带有clang
的示例(与gcc
相同):
不幸的是,Clang不支持这一点。我的软件被各种操作系统上的用户使用。他们中的一些人使用Clang(例如OS X和FreeBSD)。你可以玩一些构建技巧(例如使用
autoconf
或cmake
…)来定义你自己的HAVE_GNU GCC
宏作为真正的GCC的1…为什么你不能简单地使用memcpy
将字节复制到uint32
类型的局部变量中呢,然后对这个局部变量进行运算?这应该优化到与您的代码相同的程度,但不违反任何别名规则。我不确定编译器是否能够优化这一点。如果是这样,那就太好了。但是看到Christoph的答案,编译器似乎无法对其进行优化。Christoph的答案包含一个指向代码的链接,而该代码并没有实现我所描述的。当您希望将不同大小的缓冲区视为一系列uint64\u t
值时,该代码将整个缓冲区复制到uint64\u t
数组中(作为联合的一部分),我所描述的是使用一个uint64\t
变量并重复复制要读入其中的特定8字节。@hvd:SpookyHash对12 64位的块进行操作values@Christoph我确实知道,因为我确实测量过。:)不需要注册溢出。GCC能够将对从缓冲区复制的局部变量的访问转换为直接对该缓冲区的内存访问。代码中的局部变量不一定转换为CPU的寄存器。
clang -flto -O3 -c a.c
clang -O3 -fno-strict-aliasing b.c # no -flto and with -fno-strict-aliasing
clang -flto -O3 -c main.c
clang a.o b.o main.o -o main