О разуме компиляторов
Aug. 8th, 2017 04:11 pmИсходник:
Выхлоп gcc:
Кто-то догадался, что сократить проверку диапазона близких значений вычитанием базы - отлично.
Беззнаковое сравнение результата вычитания - очень остроумно.
xor с rax, когда достаточно с eax - чего пытаются добиться?
Финальный and с константой - разве из предыдущих команд не ясно, что там останется один бит?
Считаем контрольную сумму:
Генерируем с векторизацией. Не буду приводить всю сумасшедшую простыню, только основной цикл:
Кто может объяснить, чем нуль в xmm4 принципиально отличается от нуля в xmm6, и почему их нельзя было объединить?
В пропущенной части: до начальной границы 16 байт - короткий простой цикл по байту, но после последней такой границы - цикл развёрнут в 15 отдельных групп со сравнением в каждой на достижение конца входного массива.
Замена char на unsigned char убирает только сравнения (pcmpgt*). Два разных нуля остаются.
За окном шёл снег и два нулевых регистра.
bool FixMessage::isResendable() const
{
unsigned type = getType();
return type != FIX_MT_LOGON && type != FIX_MT_HEARTBEAT &&
type != FIX_MT_TEST_REQUEST && type != FIX_MT_RESEND_REQUEST &&
type != FIX_MT_SEQ_RESET && type != FIX_MT_LOGOUT;
}
Выхлоп gcc:
0000000000438570 <_ZNK10FixMessage12isResendableEv>:
438570: 8b 4f 0c mov 0xc(%rdi),%ecx
438573: b8 01 00 00 00 mov $0x1,%eax
438578: 83 e9 30 sub $0x30,%ecx
43857b: 83 f9 11 cmp $0x11,%ecx
43857e: 77 12 ja 438592 <_ZNK10FixMessage12isResendableEv+0x22>
438580: b8 37 00 02 00 mov $0x20037,%eax
438585: 48 d3 e8 shr %cl,%rax
438588: 83 e0 01 and $0x1,%eax
43858b: 48 83 f0 01 xor $0x1,%rax
43858f: 83 e0 01 and $0x1,%eax
438592: f3 c3 repz retq
Кто-то догадался, что сократить проверку диапазона близких значений вычитанием базы - отлично.
Беззнаковое сравнение результата вычитания - очень остроумно.
xor с rax, когда достаточно с eax - чего пытаются добиться?
Финальный and с константой - разве из предыдущих команд не ясно, что там останется один бит?
Считаем контрольную сумму:
unsigned checksum(const char *m_begin, const char *m_before_csum)
{
unsigned csum = 0;
for (const char *p = m_begin; p != m_before_csum; ++p) {
csum += *p;
}
csum &= 0xff;
return csum;
}
Генерируем с векторизацией. Не буду приводить всю сумасшедшую простыню, только основной цикл:
pxor %xmm0, %xmm0
addq %rdi, %r9
xorl %edi, %edi
pxor %xmm6, %xmm6
pxor %xmm4, %xmm4
.L9:
movdqa (%r9), %xmm3
movdqa %xmm6, %xmm1
movdqa %xmm4, %xmm5
addq $1, %rdi
pcmpgtb %xmm3, %xmm1
movdqa %xmm3, %xmm2
addq $16, %r9
cmpq %rdi, %rdx
punpcklbw %xmm1, %xmm2
punpckhbw %xmm1, %xmm3
pcmpgtw %xmm2, %xmm5
movdqa %xmm2, %xmm1
punpckhwd %xmm5, %xmm2
punpcklwd %xmm5, %xmm1
movdqa %xmm4, %xmm5
pcmpgtw %xmm3, %xmm5
paddd %xmm1, %xmm0
paddd %xmm2, %xmm0
movdqa %xmm3, %xmm2
punpcklwd %xmm5, %xmm2
paddd %xmm2, %xmm0
movdqa %xmm0, %xmm1
movdqa %xmm3, %xmm0
punpckhwd %xmm5, %xmm0
paddd %xmm1, %xmm0
ja .L9
Кто может объяснить, чем нуль в xmm4 принципиально отличается от нуля в xmm6, и почему их нельзя было объединить?
В пропущенной части: до начальной границы 16 байт - короткий простой цикл по байту, но после последней такой границы - цикл развёрнут в 15 отдельных групп со сравнением в каждой на достижение конца входного массива.
Замена char на unsigned char убирает только сравнения (pcmpgt*). Два разных нуля остаются.
За окном шёл снег и два нулевых регистра.
no subject
Date: 2017-08-08 01:26 pm (UTC)(no subject)
From:no subject
Date: 2017-08-09 05:47 pm (UTC)