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-4XOR
每个时钟。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
是一对