Проблема с пользовательским LLVM-IR для моего компилятора

Вопрос или проблема

В настоящее время я работаю над компилятором языка программирования, который генерирует LLVM-IR. Я не использую никаких библиотек для вывода, поэтому просто записываю инструкции в файл. Проблема в изменяемых переменных: я регистрирую %i, %i.(index) со значением, а затем загружаю %i с %i.(index). Это может быть не совсем правильный способ работы с изменяемыми переменными в LLVM, но это лучшее из того, что я пробовал ранее, так как они нужны мне для работы с рекурсией, например, когда я перебираю i, пока значение меньше десяти, что делает этот код возможно.

Сгенерированный код LLVM:

@.str_0 = private unnamed_addr constant [4 x i8] c"%i\0A\00"
declare i32 @printf(i8*, ...) nounwind

define i32 @add(i32 %a, i32 %b) nounwind {
entry:
    %t1 = add i32 %a, %b
    ret i32 %t1
}

define i32 @main() nounwind {
entry:
    %i = alloca i32
    %i.0 = alloca i32
    store i32 0, i32* %i.0
    store i32 %i.0, i32* %i
    %t2 = icmp slt i32 %i, 10
    br i1 %t2, label %lb1, label %lb2
lb1:
    %t3 = getelementptr [4 x i8], [4 x i8]* @.str_0, i32 0, i32 0
    %t4 = call i32 @printf(i8* %t3, i32 %i)
    %t5 = call i32 @add(i32 %i, i32 1)
    %i.1 = alloca i32
    store i32 %t5, i32* %i
    store i32 %i.1, i32* %i
    %t6 = icmp slt i32 %i, 10
    br i1 %t6, label %lb1, label %lb2
lb2:
    ret i32 0
}

Код, который генерирует мой компилятор:

fn add(a: int, b: int): int {
    return a + b;
}

fn main(): void {
    let i: int = 0;
    while (i < 10) {
        printf("%i\n", i);
        i = add(i, 1);
    }
    return;
}

Ошибка:

./out/test.zk.ll:15:15: error: '%i.0' defined with type 'ptr' but expected 'i32'
   15 |     store i32 %i.0, i32* %i
      |               ^
1 error generated.

Я надеюсь, что смогу определить изменяемую переменную, а затем изменить её значение таким образом, чтобы это работало в рекурсии.

Заранее спасибо за любую помощь.

Ответ или решение

Ваш вопрос касается проблемы с управлением изменяемыми переменными в сгенерированном LLVM IR для вашего компилятора, и, судя по вашей ошибке, проблема заключается в неправильном использовании указателей и типов. Давайте разберем это детально.

Проблема

Ваша ошибка, возникающая на строке:

store i32 %i.0, i32* %i

указывает, что вы пытаетесь сохранить на адрес, который имеет неправильный тип. Конкретно, %i.0 определен как указатель (ptr), но вы ожидаете сохранение значения типа i32. Это несоответствие типов приводит к ошибке компиляции.

Решение

Правильная работа с изменяемыми переменными в LLVM IR требует, чтобы вы корректно управляли указателями и значениями. Давайте рассмотрим, как должен выглядеть исправленный код:

  1. Выделите память для переменной i с помощью директивы alloca и используйте один указатель для хранения значения этой переменной.
  2. Необходимо не только хранить указатель в памяти, но и загружать его значение, чтобы выполнять операции с ним.

Вот исправленная версия вашей функции main():

define i32 @main() nounwind {
entry:
    %i = alloca i32             ; Аллоцируем память под переменную i
    store i32 0, i32* %i        ; Начальное значение i = 0

lb1:
    %current_value = load i32, i32* %i   ; Загружаем текущее значение i
    %t2 = icmp slt i32 %current_value, 10 ; Сравниваем i меньше 10
    br i1 %t2, label %body, label %end   ; Условный переход

body:
    %t3 = getelementptr [4 x i8], [4 x i8]* @.str_0, i32 0, i32 0
    call i32 @printf(i8* %t3, i32 %current_value) ; Печать текущего значения i
    %t5 = call i32 @add(i32 %current_value, i32 1) ; Увеличиваем i
    store i32 %t5, i32* %i        ; Сохраняем обновленное значение i
    br label lb1                  ; Переход к началу цикла

end:
    ret i32 0
}

Объяснение исправлений

  • Используется единственное alloca для переменной i.
  • store сохраняет значение 0 в i в начале.
  • Во время каждой итерации обращаемся к хранилищу i через load, а затем обновляем его значение.
  • Теперь цикл выполняется корректно, так как мы реально работаем с одним и тем же хранилищем в памяти.

Заключение

Чтобы правильно управлять изменяемыми переменными в LLVM IR, убедитесь, что вы работаете с правильными типами переменных и указателей. Модернизируя свой код согласно перечисленным выше рекомендациям, вы сможете успешно реализовать изменяемые переменные и рекурсию, соблюдая правильную типизацию.

Если у вас возникнут дополнительные вопросы, не стесняйтесь обращаться. Удачи в разработке вашего компилятора!

Оцените материал
Добавить комментарий

Капча загружается...