




Вот некоторые примеры:
#include <stdlib.h>
void test_with_self(int A){
if (A) abort();
}
void test_with_mask(int A, int Mask){
if (A&Mask) abort();
}
void test_js(int A){
if (A<0) abort();
}
void test_jns(int A){
if (A>=0) abort();
}
void cmp_jz(int A){
if (A==42) abort();
}
void cmp_jnz(int A){
if (A!=42) abort();
}
и как они могут быть отображены (clang output):
test_with_self: # @test_with_self
test edi, edi
jne .LBB0_2
ret
.LBB0_2:
push rax
call abort@PLT
test_with_mask: # @test_with_mask
test esi, edi
jne .LBB1_2
ret
.LBB1_2:
push rax
call abort@PLT
test_js: # @test_js
test edi, edi
js .LBB2_2
ret
.LBB2_2:
push rax
call abort@PLT
test_jns: # @test_jns
test edi, edi
jns .LBB3_2
ret
.LBB3_2:
push rax
call abort@PLT
cmp_jz: # @cmp_jz
cmp edi, 42
je .LBB4_2
ret
.LBB4_2:
push rax
call abort@PLT
cmp_jnz: # @cmp_jnz
cmp edi, 42
jne .LBB5_2
ret
.LBB5_2:
push rax
call abort@PLT
Обратите внимание, что je == jz и jne == jnz.
Интересно, что if () abort(); приводит к jcc с неинвертированным условием if. Поскольку компиляторы не ожидают прерывания, они делают это test/jcc/ret, так что провал — это else, а не тело if. «Стандартный» простой способ превратить C if в ассемблерную ветку — это if (!condition) goto after_if_body, как test edi,edi / jnz, как это делает clang ( godbolt.org/z/nj3qW7vrK), когда тело if sink = 1 сохраняется в глобальная переменная.
@PeterCordes Спасибо. Исправлен сбой в работе мозга, который у меня был там с test_jns. Да, похоже, clang эффективно обрабатывает условия if как неожиданные (возможно, только если там нет другой ветки). godbolt.org/z/3znzYrE1P Мне нравится, что clang также лучше реагирует на подсказки __builtin_expected. gcc, кажется, всегда делает if (!condition) goto after_if_body вещь, даже если вы делаете if (unlikely(condition)) something_returning_or_terminating, где я бы предпочел видеть прыжки на condition, а не на !condition.
jnsестьA>=0. clang правильно использовалjgдляA>0, чтобы исключить ноль: SF==OF и ZF==0. (felixcloutier.com/x86/jcc (Поскольку FLAGS были установленыtestкак сравнение с нулем, известно, что OF равно нулю, поэтому в этом случае jns и jge эквивалентны, просто SF == 0)