Комментарии 17
"не надо так"… Я прямо даже и не знаю, как сказать.
А в сях есть способ написать
dword r = a — b;
if (was_overflow) r=0;
чтоб скомпилировалось в проверку флага после вычитания?
Как в Rust'е, да? Типа checked_sub. Если я не ошибаюсь, то нет. Вычитание неотрицательных DWORD чисел само по себе уже опасно. Как мы можем сравнивать результат с нолём в отрицательную сторону?
Я не знаю, как другие бы сделали это лаконично, я бы сперва числа сравнил друг с другом перед вычитанием. Ради интереса, я сейчас изучаю Rust, и стал на эти проблемы чаще обращать своё внимание.
Я не знаю, как другие бы сделали это лаконично, я бы сперва числа сравнил друг с другом перед вычитанием. Ради интереса, я сейчас изучаю Rust, и стал на эти проблемы чаще обращать своё внимание.
Спасибо.
Интересно, а
dword r = a-b;
if (b > a) return 0; else return r;
соптимизируется на ASM уровне само или нет?
Интересно, а
dword r = a-b;
if (b > a) return 0; else return r;
соптимизируется на ASM уровне само или нет?
Несложно проверить через Compiler Explorer.
GCC (O2):
Clang (O2):
Остальные компиляторы можете попробовать по аналогии там же.
GCC (O2):
mov eax, edi
mov edx, 0
sub eax, esi
cmp edi, esi
cmovb eax, edx
ret
Clang (O2):
xor eax, eax
sub edi, esi
cmovae/cmovge eax, edi (ae for uint32_t, ge for int32_t)
ret
Остальные компиляторы можете попробовать по аналогии там же.
да, уже подёргал там в разных вариациях.
ни один из них не свернулся в sub + jo/jno…
При этом вариант с __builtin_sub_overflow сворачивается хорошо
godbolt.org/z/sq63d3
ни один из них не свернулся в sub + jo/jno…
При этом вариант с __builtin_sub_overflow сворачивается хорошо
godbolt.org/z/sq63d3
Зато на ARM получается отлично:
subs w8, w0, w1 # вычесть из w0 (a) w1 (b), положить результат в w8 (a-b)
csel w0, wzr, w8, lo # сравнить содержимое wzr (ноль) с w8 (a-b), если строго меньше, то положить в w0 (возвращаемое из функции значение) wzr (ноль), иначе w8 (a-b)
ret
В каком варианте сырка?
Что-то GCC/arm с -O3 мне даже вариант с builtin выдаёт что-то странное.
Что-то GCC/arm с -O3 мне даже вариант с builtin выдаёт что-то странное.
Кстати, а чем не устроил вариант выше с cmov? Он быстрее, чем sub/jo, потому что в нем вообще переходов нет (и потому нельзя их неверно предсказать).
Даже на -O3 нет: godbolt.org/z/dG4shf
А вот компилятор Rust'а предлагает, и в 99% случаев его предложения правильные. Почему? Потому что компилятор ууууумный. А язык правильный.
Последняя Mother of All Errors, которую я словил, добавив в невинную структуру ещё одно поле состояла из ~10 строчек, в которых мне объяснялось, что из-за этого поля (совсем в другом месте, совсем другую структуру) нельзя больше безопасно передавать между тредами. Причём в ошибке мне даже сказали, что можно ещё в одном месте заменить Fn на FnOnce, и тогда будет хорошо. Я сделал — и стало хорошо.
Рассмотрим ошибку, которую я разбирал в статье
Ошибка лютая, конечно.
Прикольно, но бессмысленно ;). Анализатор убрал код, который с точки зрения языка C++ является лишним.
А если как-то так поставить вопрос, чтобы это служило индикатором некооректной логики?
Шикарный пример, спасибо.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Почему PVS-Studio не предлагает автоматические правки кода