首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >GCC对不同的if会做什么优化?

GCC对不同的if会做什么优化?

提问于 2024-05-05 19:22:21
回答 0关注 0查看 18

有一段需要重复运行多次的代码片段:

代码语言:c
复制
if(d < 254) {
    if(d < 252)
        return data[d];
    return random_bit() ? data[d] : -data[d];
}
// other code

d 是一个 uint8_t 随机数,每次运行都随机产生。这段代码不管是执行哪个 return 都需要两次 if 判断,于是我把代码优化成了这样:

代码语言:c
复制
if(d < 252)
    return data[d];
if(d < 254)
    return random_bit() ? data[d] : -data[d];
// other code

这样将会以非常大的概率(252/256)只进行一次 if 判断,应该会比上面的代码更快。

代码使用 -Ofast 编译,按理来说这两段代码对编译器来说应该是一模一样的,GCC 应该会产生相同的机器码。但是实际上两段机器指令并不一样。

嵌套 if 反编译代码:

代码语言:txt
复制
   0x00000000004014d0 <+0>:	push   %r13
   0x00000000004014d2 <+2>:	push   %r12
   0x00000000004014d4 <+4>:	mov    %rdi,%r12
   0x00000000004014d7 <+7>:	push   %rbp
   0x00000000004014d8 <+8>:	push   %rbx
   0x00000000004014d9 <+9>:	sub    $0x18,%rsp
   0x00000000004014dd <+13>:	mov    0x200(%rdi),%rdx
   0x00000000004014e4 <+20>:	lea    0x1(%rdx),%rax
   0x00000000004014e8 <+24>:	movzbl (%rdi,%rdx,1),%ebx
   0x00000000004014ec <+28>:	mov    %rax,0x200(%rdi)
   0x00000000004014f3 <+35>:	cmp    $0x200,%rax
   0x00000000004014f9 <+41>:	je     0x401740 <function+624>
   0x00000000004014ff <+47>:	movzbl %bl,%ebp
   0x0000000000401502 <+50>:	cmp    $0xfd,%ebp                ; 与 254 比较
   0x0000000000401508 <+56>:	jg     0x401530 <function+96>
   0x000000000040150a <+58>:	cmp    $0xfb,%ebp                ; 与 252 比较
   0x0000000000401510 <+64>:	jg     0x401650 <function+384>
   0x0000000000401516 <+70>:	movsbl 0x405460(%rbp),%eax
   0x000000000040151d <+77>:	add    $0x18,%rsp
   0x0000000000401521 <+81>:	pop    %rbx
   0x0000000000401522 <+82>:	pop    %rbp
   0x0000000000401523 <+83>:	pop    %r12
   0x0000000000401525 <+85>:	pop    %r13
   0x0000000000401527 <+87>:	ret

可以看到如果小于等于 252 就会就地返回。

并列 if 反编译代码:

代码语言:txt
复制
   0x00000000004014d0 <+0>:	push   %r13
   0x00000000004014d2 <+2>:	push   %r12
   0x00000000004014d4 <+4>:	push   %rbp
   0x00000000004014d5 <+5>:	push   %rbx
   0x00000000004014d6 <+6>:	mov    %rdi,%rbx
   0x00000000004014d9 <+9>:	sub    $0x18,%rsp
   0x00000000004014dd <+13>:	mov    0x200(%rdi),%rax
   0x00000000004014e4 <+20>:	lea    0x1(%rax),%rdx
   0x00000000004014e8 <+24>:	movzbl (%rdi,%rax,1),%ebp
   0x00000000004014ec <+28>:	mov    %rdx,0x200(%rdi)
   0x00000000004014f3 <+35>:	cmp    $0x200,%rdx
   0x00000000004014fa <+42>:	je     0x401720 <function+592>
   0x0000000000401500 <+48>:	movzbl %bpl,%r13d
   0x0000000000401504 <+52>:	cmp    $0xfb,%r13d                ; 与 252 比较
   0x000000000040150b <+59>:	jle    0x4016b0 <function+480>
   0x0000000000401511 <+65>:	mov    %ebp,%eax                  ; 下面是 random_bit 的内联展开
   0x0000000000401513 <+67>:	xor    %ebp,%ebp
   0x0000000000401515 <+69>:	mov    0x5ebf4(%rip),%rdx
   0x000000000040151c <+76>:	movabs $0x4000000000000000,%r12
   0x0000000000401526 <+86>:	and    $0x1,%eax
   0x0000000000401529 <+89>:	cmp    $0xfd,%r13d                ; 与 254 比较
   0x0000000000401530 <+96>:	jg     0x4015c1 <function+241>
   0x0000000000401536 <+102>:	test   %rdx,%rdx
   0x0000000000401539 <+105>:	je     0x401730 <function+608>
   0x000000000040153f <+111>:	shr    %rdx
   0x0000000000401542 <+114>:	mov    %rdx,0x5ebc7(%rip)
   0x0000000000401549 <+121>:	mov    0x5ebb8(%rip),%rdx
   0x0000000000401550 <+128>:	mov    %rdx,%rax
   0x0000000000401553 <+131>:	shr    %rax
   0x0000000000401556 <+134>:	mov    %rax,0x5ebab(%rip)
   0x000000000040155d <+141>:	movsbl 0x405460(%r13),%eax
   0x0000000000401565 <+149>:	mov    %eax,%ecx
   0x0000000000401567 <+151>:	neg    %ecx
   0x0000000000401569 <+153>:	and    $0x1,%edx
   0x000000000040156c <+156>:	cmove  %ecx,%eax
   0x000000000040156f <+159>:	add    $0x18,%rsp
   0x0000000000401573 <+163>:	pop    %rbx
   0x0000000000401574 <+164>:	pop    %rbp
   0x0000000000401575 <+165>:	pop    %r12
   0x0000000000401577 <+167>:	pop    %r13
   0x0000000000401579 <+169>:	ret

这段代码如果小于等于 252 就会大跳到 function+480 再返回,虽然大概率只进行一次 if 判断就返回,但是由于有一个大跳,速度会比嵌套 if 慢。

应该如何理解编译器会进行这样的优化呢?按理来说不应该有这个大跳才对。

回答

和开发者交流更多问题细节吧,去 写回答
相关文章

相似问题

相关问答用户
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档