2014-09-01 2 views
9

Есть ли способ заставить встроенную функцию в Clang/LLVM?Заставить функцию встроить в Clang/LLVM

AFAIK, следующее является лишь подсказкой для компилятора, но может игнорировать запрос.

__attribute__((always_inline)) 

Я не возражаю, что компиляция завершится неудачно, если она не может встроить функцию.

ответ

9

Существует хорошее решение для компиляции с C99, который является по умолчанию Clang. Его просто используя inline атрибут.

inline void foo() {} 

Это хорошо написано в Clang's compatibility page:

По умолчанию Clang строит код C в соответствии со стандартом C99, который обеспечивает различную семантику для строкового ключевого слова, чем поведение GCC по умолчанию ...

В C99 встроенная строка означает, что определение функции предоставляется только для встраивания и что в программе есть другое определение (без встроенного). Это означает, что эта программа является неполной, потому что если добавление не включено (например, при компиляции без оптимизации), тогда у main будет неразрешенная ссылка на это другое определение. Поэтому мы получим (правильную) ошибку времени соединения ...

GCC распознает его как расширение и просто рассматривает его как подсказку к оптимизатору.

Так что для того, чтобы гарантировать, что функция встраиваемой:

  1. Не используйте статический встроенный.
  2. Не добавляйте другую реализацию для функции, которая не имеет встроенного атрибута.
  3. Вы должны использовать оптимизацию. Но даже если нет оптимизации, компиляция завершится неудачно, что хорошо.
  4. Обязательно не компилироваться с помощью GNU89.
+0

не использовать 'static inline'? я предполагаю, что таким образом вы получите сообщение об ошибке в clang (поскольку его поведение по умолчанию - c99) –

+0

Это может привести к сбою связи, если ему не удалось встроить (и функция не была объявлена ​​как статическая). Но это намерение, как я писал в вопросе: «Я не возражаю, что компиляция завершится неудачно, если она не сможет встроить функцию». – DavidS

+0

хорошо, я вижу твою идею; вы точно ответили на свой вопрос. Однако вам нужно немного странно :-) –

4

Я буду рассматривать ваш вопрос как запрашивающий любые инструменты в рамках Clang/LLVM. Вот мое предложение: скомпилируйте свой код в бит-код LLVM, а затем запустите Always inline pass.

Например:

> clang <other CFLAGS> -emit-llvm -c -o foo.bc foo.c 
> opt -always-inline foo.bc -o foo_inline.bc 
> clang -c -o foo.o foo_inline.bc 

Я использовал эту последовательность до и она встраиваемая все моих функций с пометкой «always_inline». В моем случае я уже делал другие анализы и преобразовывал в биткод, поэтому мне нужно было добавить флаг для выбора.

+0

Как это отличается от always_inline атрибута? является встроенным гарантированным при использовании этого флага с опцией? или это просто намек? – DavidS

+0

Команда opt указывает, что она запускает всегда встроенный переход трансформации на LLVM IR. Этот проход проходит через ИК-интерфейс и находит все функции с атрибутом always_inline и строит их. Глядя на исходный код - http: // llvm.org/docs/doxygen/html/InlineAlways_8cpp_source.html, комментарии указывают, что он должен содержать все, что отмечено always_inline, и это возможно. Вы можете написать пропуск, который будет терпеть неудачу, если он найдет какие-либо вызовы функции, отмеченной «always_inline». – Brian

-3

Метод грубой силы просто превращает его в макрос.

0

Всего несколько замечаний, которые могут быть полезны также.

Для замечаний Op по:

  1. Несколько static inline определения является оговоркой, поскольку это может вызвать, при изменении одного из них, нескольких различных функции, которые могут вызвать много головных царапины, особенно если встраивание кайфа и фактические звонки испаряются до разных последовательностей утверждений.
  2. Это может быть аналогичным эффектом, как 1.
  3. Inlining - это оптимизация, и вы можете посмотреть в руководстве своего компилятора, чтобы увидеть, когда он вздрагивает (например, gcc doc page). Обычно он находится на первом уровне. См. Также this ответ.

Полезное обсуждение и рекомендации можно найти here. Рекомендации для C99 суммируется следующим образом:

  1. В файле заголовка определяет следующее и включить его везде, где это необходимо:

    inline void foo() { /*...*/ }

  2. В одном исходном файле объявить его с помощью extern для генерации внешнего символа:

    extern inline foo();

Что касается предложенного метода LLVM IR, он работает, но затем вы передаете домен исходного языка и подчиняетесь другому набору правил (сильно зависящих от инструмента). Краткая ориентировочная дискуссия может быть найдена here.

+0

Я был бы признателен за конструктивную обратную связь/указатели/и т. Д., Когда вы будете опущены. – compor

0

Вы можете начать с экспериментирования с: звоном -mllvm -inline порога = п

Чем больше параметр п, тем более агрессивным встраивание будет. По умолчанию 225, поэтому установите его в нечто большее. Ожидайте большой размер кода и длительное время компиляции с очень агрессивной вставкой. Когда вы нажмете на точку уменьшения прибыли, вы можете попробовать профилировать код и посмотреть для часто вызываемых, но неинсталлированных функций и попытаться маркировать их атрибут ((always_inline)) для еще большей инкрустации.

Если у вас есть функции с пометкой «встроенный», вы также можете поэкспериментировать с -inlinehint-threshold больше, чем -inline-threshold, и посмотреть, изменяет ли этот код .

Также вы компилируете с оптимизацией времени соединения? Без них встраивание ограничено отдельными единицами компиляции.

** взяты из groups.google.com forum

Смежные вопросы