Як змусити компілювати кланг у IR IR


150

Я хочу, щоб Кланг компілював свій C/C++код у LLVMбайт-код, а не у двійковий виконуваний файл. Як я можу цього досягти? І якщо я отримаю LLVMбайт-код, як я можу взяти його для подальшого компіляції до бінарного виконуваного файлу.

В основному я хочу додати до власного коду деякий власний код, LLVMперш ніж компілювати у двійковий виконуваний файл.


Я думаю, це називається біт
кодом

Відповіді:


204

З огляду на деякий файл C / C ++ foo.c:

> clang -S -emit-llvm foo.c

Створює foo.llІР-файл LLVM.

-emit-llvmВаріант також може бути переданий в компілятор переднього кінця безпосередньо, а не водій за допомогою -cc1:

> clang -cc1 foo.c -emit-llvm

Виробляє foo.llза допомогою ІЧ. -cc1додає кілька цікавих варіантів, як -ast-print. Ознайомтеся з -cc1 --helpдетальніше.


Для компіляції LLVM IR для складання використовуйте llcінструмент:

> llc foo.ll

Виробляється foo.sпри складанні (за замовчуванням до архітектури машини, на якій ви працюєте). llcє одним із інструментів LLVM - ось його документація .


7
Що тут робить -S?
meawoppl

13
@meawoppl: -S, як у gcc каже, випускайте текстову збірку, а не збирайте двійкові
Елі Бендерський,

Ага. Мені важко було знайти що-небудь у документах про це. Чи можна припустити, що багато прапорів у структурі прапора gcc дзеркального дзеркала?
meawoppl

@EliBendersky Ви знаєте, як компілювати декілька файлів .c та .h в один читаний ІК-код, щоб я міг запускати ІК за допомогою "lli theIrFile"? Спасибі
кеш

1
@cache: компілюйте кожен у свій власний ІР-файл, а потім використовуйте лінкер LLVM для комбінування
Елі Бендерський

20

Використовуйте

clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc

9
Я рекомендую зберегти значення розширень недоторканими. IOW, .oповинен посилатися на файли бінарних об'єктів, .sна збиральні файли та щось інше (за домовленістю .ll) на ІР-файли LLVM. Інакше легко заплутатися. У Clang / LLVM тепер немає власного лінкера для бінарних об'єктів (хоча один є у роботі). Лінк LLVM llvm-ldпросто об'єднує декілька ІР-файлів в один
Елі Бендерський

1
@EliBendersky: ти маєш рацію, що стосується розширень файлів - і фронтленд clang насправді робить правильно, якщо .bcвикористовується; також майте на увазі, що це llvm-ldможе виступати в якості основи для системного ланцюга інструментів, тобто моя попередня відповідь на використання llvm-ld -nativeповинна працювати як очікувалося ....
Крістоф

1
@rickfoosusa: працює для мене - foo.bcце файл бітового коду LLVM
Крістоф

1
Роботи для мене clang -emit-llvm -o test.bc -c test.c && file test.bc: test.bc: LLVM IR bitcode.
ntc2

18

Якщо у вас є декілька вихідних файлів, ви, ймовірно, хочете використовувати оптимізацію посилання-часу для виведення одного файлу бітового коду для всієї програми. Інші наведені відповіді змусять вас отримати файл бітового коду для кожного вихідного файлу.

Натомість, ви хочете компілювати за допомогою оптимізації часу та часу

clang -flto -c program1.c -o program1.o
clang -flto -c program2.c -o program2.o

а для завершального кроку посилання додайте аргумент -Wl, -plugin-opt = також-emit-llvm

clang -flto -Wl,-plugin-opt=also-emit-llvm program1.o program2.o -o program

Це дає вам як компільовану програму, так і відповідний їй біт-код (program.bc). Потім ви можете змінити program.bc будь-яким способом, який вам подобається, і перекомпілювати змінену програму в будь-який час, зробивши це

clang program.bc -o program

хоча пам’ятайте, що на цьому кроці потрібно знову включити будь-які необхідні прапорці посилання (для зовнішніх бібліотек тощо).

Зауважте, що для цього вам потрібно використовувати золотий лінкер. Якщо ви хочете змусити Кланг використовувати певний лінкер, створіть символьне посилання на цей лінкер під назвою "ld" у спеціальному каталозі під назвою "fakebin" десь на вашому комп'ютері та додайте параметр

-B/home/jeremy/fakebin

до будь-яких етапів посилання вище.


13

Якщо у вас є декілька файлів, і вам не потрібно вводити кожен файл, я рекомендую вам дотримуватися цих простих кроків (я використовую, clang-3.8але ви можете використовувати будь-яку іншу версію):

  1. генерувати всі .llфайли

    clang-3.8 -S -emit-llvm *.c
  2. зв’язати їх в єдине ціле

    llvm-link-3.8 -S -v -o single.ll *.ll
  3. (Необов’язково) Оптимізуйте свій код (можливо, аналіз псевдоніму)

    opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
  4. Створити збірку (створює optimised.sфайл)

    llc-3.8 optimised.ll
  5. Створити виконуваний файл (названий a.out)

    clang-3.8 optimised.s

Ваше рішення досить унікальне: ви використовували "-S", а не просто залишали його як двійковий вихід. Чи є різниця між тим, що мати "-S" і не мати "-S"?
Петро Тео

@PeterTeoh Я використовую -Sпараметр (на кроці 2), я вказую, що я хотів би отримати висновок в LLVM IR. В основному, розмістіть усі * .ll файли в один. Я роблю це, щоб перевірити, чи оптимізація дійсно змінює код, тобто single.llчи optimised.llмає тепер виглядати інакше (залежно від коду), і ви також можете показати звіт, щоб побачити, чи є різниця взагалі.
Кіко Фернандес

-basicaaaнеправильний прапор, його -basicaaпотрібно використовувати.
anton_rh

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.