LLVM - Как заставить вложенную функцию видеть переменные внешней функции - PullRequest
0 голосов
/ 18 апреля 2019

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

func a()
   int x;
   func b()
      int y;
      {
       // code of func b - both x and y are visible here
      }
   {
    // code of func a - only x is visible here
   }

Я использую LLVM API в c ++ для компиляции кода.Моя проблема в том, что я не знаю, как сделать переменную x видимой в функции b, поскольку, насколько мне известно, llvm не поддерживает вложенную функцию.На данный момент я объявляю переменную следующим образом:

static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName, Type *T) {
    IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
    return TmpB.CreateAlloca(T, 0, VarName.c_str());
}

Как показано в руководстве по llvm https://llvm.org/docs/tutorial/LangImpl07.html#adjusting-existing-variables-for-mutation. При использовании этого объявления и попытке использовать внешнюю переменную во вложенной функции, этавыскакивает ошибка: Инструкция не доминирует над всеми видами использования! .
Есть ли способ исправить это?

Ответы [ 2 ]

0 голосов
/ 18 апреля 2019

LLVM поддерживает структуры, верно? Вот что делают типичные компиляторы.

Вам необходимо создать анонимную структуру с полями, сгенерированными из каждой внешней переменной, на которую вы ссылаетесь. Затем вы создаете анонимную функцию, соответствующую b(), которая принимает эту структуру в качестве аргумента и работает с ней. По сути, вы превращаете b() в обычную функцию верхнего уровня. Наконец, вы преобразуете код a() так, что он создает экземпляр структуры и вызывает анонимную функцию. На данный момент возможны дальнейшие оптимизации. Будьте готовы: это совсем не просто, возможно, очень сложная тема для преобразования кода.

Например

func a()
   int x = 1;
   func b() {
      return x+1;
   }
   return b() + 2;
}

становится

struct tmp {
    int tmpx;  // reference or value?
}
func tmp_b(tmp& instance) {
    instance.tmpx += 1;
    return instance.tmpx;
}
func a() {
    int x = 1;
    tmp instance(tmpx = x);  // should it go by reference or value?
    return tmp_b(instance) + 2;
}

В качестве альтернативы вы можете преобразовать b() в b(int x) функцию верхнего уровня. Но такой подход менее гибок ИМО. Или в зависимости от контекста использовать оба подхода, почему бы и нет.

Обратите внимание, что все это, вероятно, можно упростить, если ваш язык поддерживает надлежащие классы с перегрузкой методов и / или операторов (в данном случае оператора вызова).

0 голосов
/ 18 апреля 2019

Это не поддерживается в C ++.

Если вы хотите получить доступ к переменной таким способом из вложенной или любой другой функции, передайте ссылку на нее. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...