Оператор asm, не являющийся volatile
, обрабатывается как чистая функция своих входов: выдает один и тот же вывод каждый раз при запуске с одинаковыми явными входами.
И отдельно , без "memory"
clobber: не читает и не записывает ничего, что не было упомянуто как входной или выходной операнд.
Звучит так, как предназначены volatile и :: "memory" для обозначения побочных эффектов в памяти.
Нет, volatile
просто означает, что выходные операнды не являются чистой функцией входных операндов. "memory"
Clobber в основном ортогональный и не , подразумеваемый volatile
Пример, который вы цитировали, похоже, читает счетчик циклов %%clock
или что-то, что нужно повторять каждый раз, иначе компилятор может CSE и поднять его из всех oop. Вы не хотели бы, чтобы это заставляло компилятор проливать / перезагружать любые глобальные переменные, которые он имел в регистрах. volatile
не подразумевает побочных эффектов памяти, так что это всего лишь билет для этого варианта использования.
Для шаблона asm все равно будет ошибка считывать или записывать любые другие переменные за спиной компилятора ( не через явные "m"
, "=m"
или "+m"
операнды), потому что volatile
не подразумевает "memory"
clobber.
В GNU C inline asm даже "r"(pointer_variable)
не не подразумевает, что указанные данные читаются или записываются. Например, присваивание может быть оптимизировано как мертвые хранилища, если все, что вы делаете с переменной, это передаете указатель на нее как входные данные для оператора asm
без "memory"
Clobber. Как я могу указать, что можно использовать память, * указанную * встроенным аргументом ASM?
A "memory"
clobber заставит компилятор предположить, что любая глобально доступная память (или доступная через ввод указателя) могла быть прочитана или записана, и, таким образом, вылить / перезагрузить переменные из регистров вокруг такого оператора asm. (Если escape анализ не может доказать, что ничто иное не может иметь указатель на них, т.е. что указатель на переменную не "ускользнул" от локальной области видимости. Так же, как компиляторы решают, что они могут хранить переменную в регистр для вызова не встроенной функции.)
Так безопасен ли один "memory"
без volatile
? Нет
A "memory"
Clobber не останавливает оптимизацию оператора asm, если не используется ни один из его явных выходных операндов. (Без операндов "= ..." оператор asm
является неявно энергозависимым).
Предполагается, что энергонезависимый оператор asm с клоббером памяти изменяет любую доступную память в этой точке абстрактная машина, если / когда выполняется строка шаблона asm, но компилятор по-прежнему свободен выполнять преобразования, которые приводят к тому, что это вообще не происходит или реже, чем исходный код. (например, выведите его из al oop, если все другие переменные, которые изменяются в l oop, - это все локальные пользователи, чей адрес не избежал функции.)
Не- volatile
asm-оператор по-прежнему считается чистой функцией по отношению к. его явные входы и выходы, поэтому asm("..." : "=r"(out) : "r"(in) : "memory");
можно было бы поднять из всех oop, если l oop использовал один и тот же "in"
на каждой итерации. (Это может произойти, только если все переменные l oop являются локальными, на которые оператор asm не может иметь указатель (экранирующий анализ, как для вызова не встроенной функции). В противном случае "memory"
clobber заблокирует это переупорядочение. )
Или полностью оптимизируется, если все варианты использования "out"
могут быть оптимизированы вне зависимости от доступа к памяти вокруг оператора. Решение будет только на основе явных операндов, если вы опустите volatile
.
Не так уж много вариантов использования для "memory"
клоббера без volatile
; Вы можете представить себе его использование для описания функции, которая внутренне использует кеш для запоминания результатов. Компилятор может запускать его так часто или так редко, как ему хочется, и нам на самом деле все равно, мутировал ли внутренний кэш или нет. Это побочный эффект, но не ценный побочный эффект.
( Я предполагаю, что встроенный ассемблер CUDA имеет идентичную семантику встроенного ассемблера GNU C, как это поддерживается / реализовано в Clang / LLVM и G CC. Я действительно ничего не знаю о CUDA, поэтому все, что я сказал выше, основано на встроенном asm GNU C, потому что asm CUDA кажется идентичным. Поправьте меня, если я ошибаюсь, например, если заявления asm
без выходных операндов не являются неявно volatile
или если CUDA не имеет указателей.
Поскольку синтаксис встроенного asm GNU C был разработан для C и позже вместо этого переназначен для CUDA, это может помочь вашему понимание замысла в терминах C, включая указатели и анализ побега.)