Я использую Метки в качестве значений (нестандартное расширение) для перехода к меткам перехода.
Ниже приведена реализация конечного автомата, упрощенная для краткости, где состояния кодируются как смещения отсоответствующие метки.
// Processes char c and returns next state
// cur_state = 0 for initial state
int sm_process_char( int cur_state, char c, void *data )
{
goto *(&&Init + cur_state);
Init:
State0:
switch ( c )
{
case 'A': return (&&State_A - &&Init);
default: return (&&State_Error - &&Init);
}
State_A:
switch ( c )
{
case 'A': return (&&State_A - &&Init);
case 'B': return (&&State_B - &&Init);
default: return (&&State_Error - &&Init);
}
State_B:
switch ( c )
{
case 'A': return (&&State_A - &&Init);
case 'B': return (&&State_B - &&Init);
default: return (&&State_Error - &&Init);
}
State_Error:
return cur_state;
}
Сборка, сгенерированная этим кодом, далека от оптимальной с -O3
:
sm_process_char:
movsx rax, edi
add rax, OFFSET FLAT:.L2
jmp rax
.L5:
.L9:
cmp sil, 65
je .L8
cmp sil, 66
je .L10
.L4:
mov edi, OFFSET FLAT:.L7
sub rdi, OFFSET FLAT:.L2
mov eax, edi
ret
.L7:
mov eax, edi
ret
.L2:
cmp sil, 65
jne .L4
.L8:
mov edi, OFFSET FLAT:.L5
sub rdi, OFFSET FLAT:.L2
mov eax, edi
ret
.L10:
mov edi, OFFSET FLAT:.L9
sub rdi, OFFSET FLAT:.L2
mov eax, edi
ret
Обратите внимание на инструкции mov
и sub
, вычисляющие разницу всмещения.Я ожидал, что это можно будет сделать во время компиляции и заменить на отдельные mov
инструкции.
Можно ли заставить GCC / Clang вычислять их во время компиляции и получить лучшую сборку?
Годболт ссылка здесь: https://godbolt.org/z/zZdFYo