Я делаю компилятор для подмножества PHP, используя LLVM и OCaml. Учебников по обработке строк в LLVM немного не хватает — по крайней мере, я не могу их найти.
Это код, который я хочу скомпилировать:
<?php
$a = "foo";
Это мой набранный AST для приведенного выше кода:
[(Typedast.Stmt
Typedast.Expr (Typedast.TUnit,
(<opaque>,
Typedast.Binop ((Typedast.Eq None),
(<opaque>, Typedast.Lvar ((<opaque>, "$a"), Typedast.TString)),
(<opaque>, (Typedast.String (<opaque>, "asd"))), Typedast.TUnit))))]
(<opaque>
здесь просто означает, что pos
(позиция) не отображается.)
Это мой сгенерированный LLVM IR:
; ModuleID = 'mymodule'
@foo = private unnamed_addr constant [4 x i8] c"foo\00"
define i32 @main() {
entry:
%"$a" = alloca i8
store i8 0, i8* %"$a"store i8* getelementptr inbounds ([4 x i8]* @foo, i32 0, i32 0), i8* %"$a"ret i32 0
}
И мое сообщение об ошибке:
Stored value type does not match pointer operand type!
store i8* getelementptr inbounds ([4 x i8]* @asd, i32 0, i32 0), i8* %"$a"i8LLVM ERROR: Broken module found, compilation aborted!
Проблема в том, что i8* %"$a"
должно быть i8** %"$a"
, как показано в LLVM IR для простой C-программы:
int main() {
char* str = "Hello, world!";
puts(str);
return 0;
}
который сгенерирует этот LLVM IR:
@.str = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1
; Function Attrs: nounwind uwtable
define i32 @main() #0 {
%1 = alloca i32, align 4
%str = alloca i8*, align 8
store i32 0, i32* %1
store i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0), i8** %str, align 8
%2 = load i8** %str, align 8
%3 = call i32 @puts(i8* %2)
ret i32 0
}
Любая помощь приветствуется.
Решено (я очень надеюсь) путем изменения кода размещения. Вместо
build_alloca i8_t ...
так должно быть
build_alloca (pointer_type i8_t) ...
Я отлаживал это, редактируя сгенерированный код напрямую, а затем компилируя его с помощью llc, чтобы увидеть, что нужно изменить.
Других решений пока нет …