-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Open
Description
look at this emample:
https://godbolt.org/z/jrrK8q3Ex
#include <stdbool.h>
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
extern int xxx;
void temp(void)
{
if (({
const bool __ret_do_once = unlikely(xxx != 2); // define unlikely here
static bool __attribute__((__section__(".data..once"))) __already_done;
if (__ret_do_once && !__already_done)
__already_done = true; // -> unlikely path
__ret_do_once;
}))
__asm__ volatile ("nop":::); // -> unlikely path
}The assemble of clang is:
temp: # @temp
.cfi_startproc
movq xxx@GOTPCREL(%rip), %rax
movl (%rax), %eax
cmpl $2, %eax
je .LBB0_3 // eax ==2 is likely, so here jmp likely
testb $1, temp.__already_done(%rip)
jne .LBB0_3
movb $1, temp.__already_done(%rip)
jmp .LBB0_4
.LBB0_3:
cmpl $2, %eax // eax is not changed, so jmp again
je .LBB0_5
.LBB0_4:
#APP
nop
#NO_APP
.LBB0_5:
retq
The gcc assemble is :
temp:
cmpl $2, xxx(%rip)
jne .L5 // jump unlikely right
ret // likely run here, return fast
.L5:
cmpb $0, __already_done.0(%rip)
jne .L3
movb $1, __already_done.0(%rip)
.L3:
nop
ret
This results in all the WARN_ONCE branches in the Linux kernel source code being judged twice, causing significant performance loss:
https://elixir.bootlin.com/linux/v6.18-rc4/source/include/linux/once_lite.h#L19