我对GCC的优化标志及其工作方式有疑问。
我有一段很长的代码,它利用了所有本地数组和变量。在代码的最后,我将本地数组的内容复制到全局数组。这是我的代码的一个非常简化的例子:
uint8_t globalArray[16]={0};
void func()
{
unsigned char localArray[16]={0};
for (int r=0; r<1000000; r++)
{
**manipulate localArray with a lot of calculations**
}
memcpy(&globalArray,localArray,16);
}
以下是三种不同场景中代码的近似速度:
没有&#34; -O3&#34;优化:3.203s
使用&#34; -O3&#34;优化:1.457s
使用&#34; -O3&#34;优化和不最终memcpy(&globalArray,localArray,16);
声明:0.015s
不将本地数组复制到全局数组中,代码运行速度快了近100倍。我知道全局数组存储在内存中,本地数组存储在寄存器中。我的问题是:
为什么只将本地数组的16个元素复制到全局数组会导致执行速度慢100倍?我在这个论坛和网上搜索过,我找不到这个特殊场景的明确答案。
有没有办法可以在没有速度损失的情况下提取局部变量的内容?
提前感谢任何可以帮助我解决此问题的人。
答案 0 :(得分:7)
如果没有memcpy
,您的编译器可能会看到永远不会读取localArray
,因此它不需要在循环体中进行任何计算。
以此代码为例:
uint8_t globalArray[16]={0};
void func()
{
unsigned char localArray[16]={0};
for (int r=0; r<1000000; r++)
{
localArray[r%16] = r;
}
memcpy(&globalArray,localArray,16);
}
Clang 3.7.1 -O3
输出此程序集:
func(): # @func()
# BB#0:
xorps %xmm0, %xmm0
movaps %xmm0, -24(%rsp)
#DEBUG_VALUE: r <- 0
xorl %eax, %eax
.LBB0_1: # =>This Inner Loop Header: Depth=1
#DEBUG_VALUE: r <- 0
movl %eax, %ecx
sarl $31, %ecx
shrl $28, %ecx
leal (%rcx,%rax), %ecx
andl $-16, %ecx
movl %eax, %edx
subl %ecx, %edx
movslq %edx, %rcx
movb %al, -24(%rsp,%rcx)
leal 1(%rax), %ecx
#DEBUG_VALUE: r <- ECX
movl %ecx, %edx
sarl $31, %edx
shrl $28, %edx
leal 1(%rax,%rdx), %edx
andl $-16, %edx
negl %edx
leal 1(%rax,%rdx), %edx
movslq %edx, %rdx
movb %cl, -24(%rsp,%rdx)
leal 2(%rax), %ecx
movl %ecx, %edx
sarl $31, %edx
shrl $28, %edx
leal 2(%rax,%rdx), %edx
andl $-16, %edx
negl %edx
leal 2(%rax,%rdx), %edx
movslq %edx, %rdx
movb %cl, -24(%rsp,%rdx)
leal 3(%rax), %ecx
movl %ecx, %edx
sarl $31, %edx
shrl $28, %edx
leal 3(%rax,%rdx), %edx
andl $-16, %edx
negl %edx
leal 3(%rax,%rdx), %edx
movslq %edx, %rdx
movb %cl, -24(%rsp,%rdx)
leal 4(%rax), %ecx
movl %ecx, %edx
sarl $31, %edx
shrl $28, %edx
leal 4(%rax,%rdx), %edx
andl $-16, %edx
negl %edx
leal 4(%rax,%rdx), %edx
movslq %edx, %rdx
movb %cl, -24(%rsp,%rdx)
addl $5, %eax
cmpl $1000000, %eax # imm = 0xF4240
jne .LBB0_1
# BB#2:
movaps -24(%rsp), %xmm0
movaps %xmm0, globalArray(%rip)
retq
对于没有memcpy
的相同代码,它会输出:
func(): # @func()
# BB#0:
#DEBUG_VALUE: r <- 0
retq
即使你对装配一无所知,但很清楚看到后者什么都不做。