Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.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++ 如何让GCC优化长XOR链_C++_Gcc_Compiler Optimization - Fatal编程技术网

C++ 如何让GCC优化长XOR链

C++ 如何让GCC优化长XOR链,c++,gcc,compiler-optimization,C++,Gcc,Compiler Optimization,我有一个像这样的循环: uint32_t result = 0; for ( int i = 0; i < CONSTANT; ++i ) { result ^= expr; } return result; uint32\u t结果=0; 对于(int i=0;i

我有一个像这样的循环:

uint32_t result = 0;

for ( int i = 0; i < CONSTANT; ++i )
{
    result ^= expr;
}
return result;
uint32\u t结果=0;
对于(int i=0;i<常数;++i)
{
结果^=expr;
}
返回结果;
总的来说,GCC使用这段代码做得很好。它完全展开循环并为
expr
生成最佳代码。但是,它执行
结果
XOR
常量
次数。它可以是累积部分结果,然后按层次将它们异或在一起


<>我怀疑如果我用宏来展开这个操作,我可以手动完成(<代码>常数<代码>不是很大),但我想知道为什么它没有看到这个,或者如果我做的是某种晦涩的C++语言规则来阻止它。

这里可能没有积累部分结果的好处。如果您使用分治策略(异或偶数将大小减半,然后重复,每次将操作数减半),您仍然会执行
O(常量)
工作(一半的工作加上四分之一的工作加上八分之一的工作,等等,最终执行
常量-1
操作)


在块中累积部分结果的行为相同。基本上,您必须具有
常量-1
异或操作。由于这些是固定宽度的寄存器,而不是任意精度的整数,所以每个异或的工作是相同的。除非并行化
expr
工作,否则您不太可能从更复杂的方法中获得任何收益。

对于您的循环,或者
expr
不依赖于
i
,在这种情况下,
gcc
应该整体优化循环1,或者在这种情况下,
gcc
仍然可以对其进行优化(因为循环边界是恒定的,所以可以预先计算整个循环)

但似乎是这样,除非你
-march=haswell
。这看起来很奇怪,但我确实看到过这种情况

在任何情况下2,您都提到
expr
编译为两条指令。为
xor
、循环增量和测试指令添加3条指令后,您已经有5条指令用于此循环,这超过了即使是高端x86 CPU的失效率,因此在这里寻找额外的指令级并行性没有任何好处(除非您可能正在编译为宽度更高的非x86 arch?)


1…它一般是这样的,反正在
-O3


2我们只能在这里猜测一下,因为您确实在严格保护
expr
的秘密。

expr看起来像什么?expr到底是什么?也许我在这里遗漏了一些东西,但“按层次将它们异或”是否仍然需要相同总数的异或操作?“这可能是累积部分结果,然后按层次将它们异或在一起。“为什么你认为这样更好?不管是什么原因,你认为编译器是如何知道的?@DavidSchwartz它打破了依赖链。现在大多数处理器每个周期可以运行3或4条
XOR
指令。但除非你打破依赖链使它们可并行化,否则你无法利用这种吞吐量。”(在教学层面)。OP的原始代码有一个由
XOR
s组成的依赖链。在前一个代码完成之前,每个代码都无法执行。今天的大多数处理器都可以运行3或4条
XOR
指令/周期,但前提是它们是独立的。因此,虽然工作量仍然相同,但ILP会有所增加。@Mystical:除了OP的工作之外,还有一个未指定的任务在异或输入之前正在计算的表达式。假设它不是完全琐碎的,则计算
expr
所需的工作可能会干扰理想的3-4
XOR
每个时钟。
expr
指令也可能类似地简单(add,sub)因此,无论如何都要让东西被占用,或者更昂贵,从而成为一个瓶颈,使
XOR
工作“免费”(也就是说,前一个“循环”的
XOR
在下一个
expr
完成之前就已经解决了,所以依赖链不是问题)。在特定情况下,您可以通过分而治之的方法对此进行优化,但这可能需要临时存储来实现(计算多个
expr
s、
XOR
它们一起,计算更多,
XOR
它们一起,等等)。但是,如果这会导致中间产物从寄存器溢出到堆栈,那么这不太可能是一个值得的折衷。这是正确的答案。我习惯于考虑SIMD,在那里我可以通过将其分解为子问题来获得并行性。但这里没有SIMD,因此您的分析是正确的。ShadowRanger-至少在某种程度上“临时存储”可能是免费的,以寄存器的形式。当然,它们是有限的,但您不需要完全“树化”"不管怎么说,xor链——足以利用目标体系结构提供的ILP。不管怎么说,讨论细节非常困难,因为@BenJackson出于某种原因拒绝澄清
expr
的性质,因此我们无法实际分析实际行为。我的问题包含了获得正确答案所需的所有信息答案(我已经标出),在这种情况下,我对如何最好地计算一长串XOR的模糊思考是不正确的。因此,从这个意义上说,Stackoverflow对我来说是有用的,即使是不必要的敌意。我想我的意图是鼓励我删除我的问题,这样其他人就不会从中受益。顺便说一句,这不在x86上。@BenJackson-当然不是有必要的信息。我认为你实际上是对的,
gcc
应该使用
xor
的关联性使计算更加并行,但这取决于
expr
的性质和架构的宽度(特别是
gcc
的机器模式中的宽度).知道
expr
是一对