> не может быть UB в LLVM-коде, если во входном коде его нет.
Могут быть ооперации, обладающие UB, но сам компилятор при этом гарантирует, что случаев UB не будет.
Здесь речь вот о чём. Допустим, что в программе на определённом ЯВУ нет UB, и каждая операция, например, сложения имеет проверку на переполнение. Но оптимизирующий компилятор может выбросить эти проверки, если он видит, что переполнение невозможно, и сгенерировать код на IR, в котором есть UB.
И в этом ничего плохого нет, поэтому и получается, что UB != Unsafe.
Я с вами абсолютно согласен. Поэтому автор и пишет, что можно сделать без UB игрушечный язык или подмножество реального языка, но на практике наличие UB является неизбежным.
Вы знаете что clang тоже генерит не оптимизированный llvm ir, где все переменные выделяются на стеке?
Да, знаю. Посмотрите ещё раз внимательно приведённый в статье код до оптимизации и после.
Оптимизатор удалил стековые копии «симулируемых регистров», и всё, что он сейчас может сделать, это вычислять адрес через операции с «виртуальным» регистром RSP и делать операции load/store volatile с полученным адресом. Обращения к волатильным переменным не могут быть удалены оптимизатором, а неволатильными их сделать тоже нельзя, потому что McSema ничего не знает о реальных переменных исходной программы.
Надеюсь. такое объяснение понятно. Если нет, попробуйте вникнуть в приведённый код, до оптимизации и после.
Лично я не пробовал, потому что у меня нет IDA Pro, а разбираться с альтернативами долго и сложно. Но парни из одной компании пробовали, и любезно предоставили мне результаты (дизассемблированный бинарник, LLVM IR до оптимизации и после оптимизации). По их словам, они пробовали компилировать под Cortex A57, у них получилось около 1% производительности по сравнению с исходным вариантом (под x86-64). К сожалению, подробностей об условиях и методах тестирования мне неизвестно.
>геометрическая фигура- не имеющая на плоскости состояния устойчивого равновесия.
Это какая? Если имеется в виду гёмбёц, у него есть одна точка устойчивого равновесия и одна неустойчивого.
Если честно, я не совсем понимаю смысла изучения ассеблерного кода, кроме тех случаев, когда мы изучаем работу непосредственно компилятора.
В том же clang-е большое число проходов оптимизации, и общее количество изменений, которые они могут внести в код в разных обстоятельствах, достигает астрономических величин.
Может быть интересно сравнивать разные реализации одной и той же функции, чтобы понять, какая из них более оптимальна, но пытаться выявить и запомнить все комбинации ассемблерных команд на выходе компилятора — бесполезное дело, имхо.
Чтобы совсем далеко не ходить, можно зайти на godbolt.org и сравнивать любой компилятор с любым.
И да, рассматривать ассемблер таргета малоэффективно, потому что для другого таргета он будет совсем другим. Более информативно смотреть промежуточный код.
Они тестируют разные вещи.
Тесты Google Test вызывают LLVM API, тесты LIT содержат исходники на LLVM IR, запускают скомпилированные части LLVM, например, opt на этих исходниках, и сравнивают результат оптимизации/компиляции с ожидаемым.
Могут быть ооперации, обладающие UB, но сам компилятор при этом гарантирует, что случаев UB не будет.
И в этом ничего плохого нет, поэтому и получается, что UB != Unsafe.
Да, знаю. Посмотрите ещё раз внимательно приведённый в статье код до оптимизации и после.
Оптимизатор удалил стековые копии «симулируемых регистров», и всё, что он сейчас может сделать, это вычислять адрес через операции с «виртуальным» регистром RSP и делать операции load/store volatile с полученным адресом. Обращения к волатильным переменным не могут быть удалены оптимизатором, а неволатильными их сделать тоже нельзя, потому что McSema ничего не знает о реальных переменных исходной программы.
Надеюсь. такое объяснение понятно. Если нет, попробуйте вникнуть в приведённый код, до оптимизации и после.
Без них обзор не выглядит полным.
Это какая? Если имеется в виду гёмбёц, у него есть одна точка устойчивого равновесия и одна неустойчивого.
И gcc, и clang.
В том же clang-е большое число проходов оптимизации, и общее количество изменений, которые они могут внести в код в разных обстоятельствах, достигает астрономических величин.
Может быть интересно сравнивать разные реализации одной и той же функции, чтобы понять, какая из них более оптимальна, но пытаться выявить и запомнить все комбинации ассемблерных команд на выходе компилятора — бесполезное дело, имхо.
При -O1 и больше имеем:
И да, рассматривать ассемблер таргета малоэффективно, потому что для другого таргета он будет совсем другим. Более информативно смотреть промежуточный код.
Тесты Google Test вызывают LLVM API, тесты LIT содержат исходники на LLVM IR, запускают скомпилированные части LLVM, например, opt на этих исходниках, и сравнивают результат оптимизации/компиляции с ожидаемым.
Разумеется, я ничего специально не отрезал, вставил в том виде, в котором нашёл.