Ответ 1
Разработчики GCC приложили определенные усилия, чтобы заставить компилятор вести себя "как ожидалось" в этих случаях. (Хотелось бы, чтобы я мог дать вам правильную ссылку для этого - я помню, что это появилось в списке рассылки или в какой-то момент).
Во всяком случае, что-то вы говорите:
... не выполняет функцию, поскольку она может использовать строгий псевдоним
... подразумевает, возможно, небольшое недоразумение того, для чего предназначены правила строгого сглаживания. Ваш пример кода вызывает поведение undefined - поэтому любая компиляция технически достоверна, включая просто обычный ret
или генерацию команды trap, или даже ничего (допустимо предположить, что метод никогда не может быть вызван). Более поздние версии GCC для получения более длинного/медленного кода вряд ли являются недостатком, поскольку код, который делает какую-либо конкретную вещь вообще, не будет нарушать стандарт. Фактически, более новые версии улучшают ситуацию, создавая код, который делает то, что программист, вероятно, намеревался сделать, вместо того, чтобы молча делать что-то другое.
Что бы вы предпочли - что компилятор создает быстрый код, который не делает то, что вам нужно, или немного медленнее, чем тот, который вам нужен?
Сказав это, я твердо верю, что вы не должны писать код, который нарушает строгие правила псевдонимов. Опираясь на компилятор, делающий "правильную" вещь, когда "очевидно", что предназначен, идет по канату. Оптимизация уже достаточно сложная, без того, чтобы компилятор должен был угадать - и сделать скидку на то, что планировал программист. Кроме того, возможно написать код, который подчиняется правилам и который может быть превращен в очень эффективный объектный код компилятором. В самом деле, можно задать следующий вопрос:
Почему предыдущие версии GCC ведут себя так, как они делали, и "оптимизировали" эту функцию, полагаясь на соблюдение правил строгой алиасии?
Это немного сложно, но интересно для этого обсуждения (особенно в свете предложений о том, что компилятор собирается до некоторой длины просто сломать код). Строгое сглаживание является компонентом (или, скорее, правилом, которое помогает) процессом, называемым alias analysis. Этот процесс решает, являются ли два указателя псевдонимами или нет. Существуют, по существу, 3 возможных условия между любыми двумя указателями:
- Они НЕ ДОЛЖНЫ АЛИА (строгое правило сглаживания позволяет легко вывести это условие, хотя иногда его можно вывести другими способами).
- Они ДОЛЖНЫ ALIAS (для этого требуется анализ, например, распространение значения может обнаружить это условие)
- Они МОГУТ АЛИАС. Это условие по умолчанию, когда ни одно из двух других условий не может быть установлено.
В случае кода в вашем вопросе строгое сглаживание подразумевает условие ДОЛЖНО НЕ АЛИАС между &acopy
и ptr
(тривиально сделать это определение, потому что два значения имеют несовместимые типы, которые не допускаются псевдоним). Это условие позволяет оптимизировать, что вы тогда видите: все манипуляции с значениями *ptr
могут быть отброшены, потому что они не могут теоретически влиять на значение acopy
, и они иначе не выходят из функции (что может быть определено с помощью эвакуационного анализа).
Требуется дополнительное усилие для определения условия MUST ALIAS между двумя указателями. Кроме того, при этом компилятору необходимо будет игнорировать (по крайней мере временно) ранее установленное условие НЕ ДОЛЖНО АЛИАС, а это означает, что он должен тратить время, пытаясь выяснить правду о состоянии, которое, если все так, как должно быть, должно быть ложь.
Когда определены условия как НЕ ДОЛЖНЫ АЛИАСЫ, так и ДОЛЖНЫ АЛИА, мы имеем случай, когда код должен вызывать поведение undefined (и мы можем выпустить предупреждение). Затем мы должны решить, какое условие сохранить и от чего отказаться. Поскольку MUST NOT ALIAS, в этом случае, исходит из ограничения, которое может быть (и действительно было) нарушено пользователем, это лучший вариант для отказа.
Таким образом, более старые версии GCC либо не выполняют необходимый анализ, чтобы определить условие MUST ALIAS (возможно, потому, что уже установлено условие MUST NOT ALIAS), или, альтернативно, более старая версия GCC выбирает отказ от MUST Условие ALIAS предпочтительнее условия MUST NOT ALIAS, что приводит к более быстрому коду, который не делает то, что, по-видимому, предполагал программист. В любом случае кажется, что новые версии предлагают улучшение.