Как бы вы повторно использовали реализации кода операции C при написании JIT с LLVM? - PullRequest
7 голосов
/ 02 февраля 2009

В руководствах и примерах llvm компилятор выводит LLVM IR, совершая подобные вызовы

return Builder.CreateAdd(L, R, "addtmp");

но многие переводчики пишутся так:

switch (opcode) {
     case ADD:
             result = L + R;
             break;
     ...

Как бы вы извлекли каждый из этих фрагментов кода для создания JIT с LLVM без необходимости повторной реализации каждого кода операции в IR LLVM?

1 Ответ

9 голосов
/ 03 февраля 2009

Хорошо, сначала возьмите все свои фрагменты кода и реорганизуйте их в свои собственные функции. Итак, ваш код идет к:

void addOpcode(uint32_t *result, uint32_t L, uint32_t R) {
    *result = L + R;
}

switch (opcode) {
    case ADD:
            addOpcode(&result, L, R);
            break;
     ....

Хорошо, после этого ваш переводчик все равно должен работать. Теперь возьмите все новые функции и поместите их в свой файл. Теперь скомпилируйте этот файл, используя llvm-gcc или clang, и вместо генерации нативного кода скомпилируйте его, используя "cpp" backend (-march -cpp). Это сгенерирует код C ++, который создает экземпляр байтового кода для модуля компиляции. Вы можете указать опции, чтобы ограничить его определенными функциями и т. Д. Вы, вероятно, хотите использовать "-cppgen module".

Теперь вернемся назад, чтобы ваш цикл интерпретатора склеил вызовы сгенерированного кода C ++ вместо непосредственного выполнения исходного кода, затем передайте его некоторым оптимизаторам и собственному генератору кода. Спасибо за JIT ;-) Вы можете увидеть пример этого в нескольких проектах LLVM, таких как vm_ops в llvm-lua .

...