Встроенная сборка clang (LLVM) - множество ограничений с бесполезными разливами / перезагрузками
clang / gcc: некоторые встроенные операнды сборки могут быть удовлетворены несколькими ограничениями, например, "rm"
, когда операнд может быть удовлетворен регистром или ячейкой памяти. Например, умножение 64 x 64 = 128 бит:
__asm__ ("mulq %q3" : "=a" (rl), "=d" (rh) : "%0" (x), "rm" (y) : "cc")
Сгенерированный код появляется, чтобы выбрать ограничение памяти для аргумента 3
, что было бы хорошо, если бы мы были зарегистрированы голодать, чтобы избежать разлива. Очевидно, что на x86-64 меньше регистровое давление, чем на IA32. Однако сгенерированный фрагмент сборки (clang):
movq %rcx, -8(%rbp)
## InlineAsm Start
mulq -8(%rbp)
## InlineAsm End
Выбирать ограничение памяти явно бессмысленно! Изменение ограничения на: "r" (y)
Однако (форсируя регистр) получаем:
## InlineAsm Start
mulq %rcx
## InlineAsm End
как и ожидалось. Эти результаты относятся к clang / LLVM 3.2 (текущий выпуск Xcode). Первый вопрос: почему в этом случае clang выбирает менее эффективное ограничение?
Во-вторых, существует менее широко используемый синтаксис множественных альтернатив с разделением запятыми:"r,m" (y)
, который должен оценить стоимость каждой альтернативы и выбрать тот, который приводит к меньшему количеству копирования. Похоже, это работает, но Clang просто выбирает первое - о чем свидетельствуют: "m,r" (y)
Я мог бы просто бросить "m"
альтернативные ограничения, но это не выражает диапазон возможных юридических операндов. Это подводит меня ко второму вопросу: были ли эти проблемы решены или хотя бы признаны в 3.3? Я попытался просмотреть архивы разработчиков LLVM, но я бы предпочел получить ответы на некоторые вопросы, прежде чем излишне ограничивать ограничения, или присоединяться к обсуждениям проекта и т. Д.
1 ответ
У меня был ответ на cfe-dev (список разработчиков внешнего интерфейса clang) от одного из разработчиков:
LLVM в настоящее время всегда выдает ограничения "rm", чтобы упростить обработку встроенного asm в бэкэнде (вы можете спросить у llvmdev, если вам нужны подробности). Я не знаю никаких планов исправить это в ближайшем будущем.
Так что это явно "известная" проблема. Одна из целей clang - правильно обрабатывать синтаксис встроенных сборок gcc, помимо других расширений, что он и делает в этом случае - просто не очень эффективно. Короче говоря, это не ошибка, как таковая.
Поскольку это не ошибка, я собираюсь продолжить с "r,m"
Синтаксис ограничений. Я считаю, что это лучший компромисс на данный момент. gcc
выберет лучшее - предположительно регистр, где это возможно - и clang
принудительно использует регистр, игнорируя дополнительные параметры после запятой. Если ничего другого, он все еще сохраняет семантическое намерение оператора сборки, т. Е. Описывает возможные ограничения, даже если они игнорируются.
Последнее замечание (20130715): этот конкретный пример не будет компилироваться с использованием "r,m"
ограничение в одной позиции - мы должны были бы предоставить альтернативное соответствие ограничения для каждого, например,
: "=a,a" (rl), "=d,d" (rh) : "%0,0" (x), "r,m" (y)
Это требуется для нескольких альтернативных ограничений с GCC. Но мы попадаем на территорию, где GCC, как известно, в прошлом обнаруживал ошибки - независимо от того, верно ли это в версии 4.8.1, я не знаю. Clang работает без альтернатив в других ограничениях, что несовместимо с синтаксисом GCC и поэтому должно рассматриваться как ошибка.
Если производительность критична, используйте "r"
иначе придерживайтесь "rm"
и, возможно, Clang решит эту проблему в будущем, даже если это принесет пользу GCC.