Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.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
C++ 是否可以启用链接时间优化,同时仅禁用某些函数的严格别名?_C++_C_Strict Aliasing - Fatal编程技术网

C++ 是否可以启用链接时间优化,同时仅禁用某些函数的严格别名?

C++ 是否可以启用链接时间优化,同时仅禁用某些函数的严格别名?,c++,c,strict-aliasing,C++,C,Strict Aliasing,我的程序遵循严格的别名规则,除了一个地方:一个编译单元,它包含杂凑函数,如MurruldHash3、SpookyHash等。在x86和x86_64上,这些杂凑函数接受一个const char*,将它们强制转换为uint32,并以4字节的块处理数据。这使得它们比逐字节处理数据快得多,但我相信这打破了严格的别名规则。现在,我用-fno严格别名编译这个编译单元,而用-fstrict别名编译程序的其余部分 但我想知道如果启用链接时间优化会发生什么。据我所知,GCC和Clang通过将程序源代码存储到.o文

我的程序遵循严格的别名规则,除了一个地方:一个编译单元,它包含杂凑函数,如MurruldHash3、SpookyHash等。在x86和x86_64上,这些杂凑函数接受一个
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