Я очень расстроен, так как эта проблема беспокоила меня в течение многих дней, поэтому я буду признателен за любую возможную помощь.
В настоящее время я создаю свой собственный язык программирования и в настоящее время пытаюсь реализовать перечисления и операторы сопоставления, которые соответствуют значению с регистром перечисления, и выполняет соответствующий оператор, но я получаю неожиданные результаты и ошибки segfaults здесь и там.
Вот один фрагмент кода моего языка, который работает (lli), но дает неожиданные результаты иногда (печатает 1, а не 3 по некоторым причинам):
class Node {
fld value: int;
fld next: OptionalNode;
new(_value: int, _next: OptionalNode) {
value = _value;
next = _next;
}
}
enum OptionalNode {
val nil;
val some(Node);
}
fun main(): int {
var s: OptionalNode = OptionalNode.some(new Node(3, OptionalNode.nil));
match s {
OptionalNode.some(n) => print n.value;
}
var r: int = 0;
ret r;
}
Это соответствующий IR LLVM, который генерирует мой компилятор:
; ModuleID = 'test.bc'
source_filename = "test"
%test.Node = type { i32, %test.OptionalNode }
%test.OptionalNode = type { i8, [8 x i8] }
%test.OptionalNode.nil = type { i8 }
%test.OptionalNode.some = type { i8, %test.Node* }
@str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
declare i32 @printf(i8*, ...)
define void @"test.Node.!ctor$[test.Node]i[test.OptionalNode]"(%test.Node* %this, i32 %_value, %test.OptionalNode %_next) {
entry:
%arg0 = alloca %test.Node*, align 8
store %test.Node* %this, %test.Node** %arg0
%arg1 = alloca i32, align 4
store i32 %_value, i32* %arg1
%arg2 = alloca %test.OptionalNode, align 16
store %test.OptionalNode %_next, %test.OptionalNode* %arg2
%ldarg1 = load i32, i32* %arg1
%tmpld_cls = load %test.Node*, %test.Node** %arg0
%tmpfld = getelementptr inbounds %test.Node, %test.Node* %tmpld_cls, i32 0, i32 0
store i32 %ldarg1, i32* %tmpfld
%ldarg2 = load %test.OptionalNode, %test.OptionalNode* %arg2
%tmpld_cls1 = load %test.Node*, %test.Node** %arg0
%tmpfld2 = getelementptr inbounds %test.Node, %test.Node* %tmpld_cls1, i32 0, i32 1
store %test.OptionalNode %ldarg2, %test.OptionalNode* %tmpfld2
ret void
}
define i32 @"test.main$v"() {
entry:
%s = alloca %test.OptionalNode, align 16
%enm = alloca %test.OptionalNode
%0 = bitcast %test.OptionalNode* %enm to %test.OptionalNode.nil*
%1 = getelementptr inbounds %test.OptionalNode.nil, %test.OptionalNode.nil* %0, i32 0, i32 0
store i8 0, i8* %1
%2 = load %test.OptionalNode, %test.OptionalNode* %enm
%tmpalloc = alloca %test.Node
call void @"test.Node.!ctor$[test.Node]i[test.OptionalNode]"(%test.Node* %tmpalloc, i32 3, %test.OptionalNode %2)
%enm1 = alloca %test.OptionalNode
%3 = bitcast %test.OptionalNode* %enm1 to %test.OptionalNode.some*
%4 = getelementptr inbounds %test.OptionalNode.some, %test.OptionalNode.some* %3, i32 0, i32 0
store i8 1, i8* %4
%5 = getelementptr inbounds %test.OptionalNode.some, %test.OptionalNode.some* %3, i32 0, i32 1
store %test.Node* %tmpalloc, %test.Node** %5
%6 = load %test.OptionalNode, %test.OptionalNode* %enm1
store %test.OptionalNode %6, %test.OptionalNode* %s
%7 = getelementptr inbounds %test.OptionalNode, %test.OptionalNode* %s, i32 0, i32 0
%8 = load i8, i8* %7
switch i8 %8, label %match_end [
i8 1, label %case1
]
case1: ; preds = %entry
%n = alloca %test.Node*, align 8
%9 = bitcast %test.OptionalNode* %s to %test.OptionalNode.some*
%10 = getelementptr inbounds %test.OptionalNode.some, %test.OptionalNode.some* %9, i32 0, i32 1
%11 = load %test.Node*, %test.Node** %10
store %test.Node* %11, %test.Node** %n
%tmpld_cls = load %test.Node*, %test.Node** %n
%tmpgetfldgep = getelementptr inbounds %test.Node, %test.Node* %tmpld_cls, i32 0, i32 0
%tmpgetfldld = load i32, i32* %tmpgetfldgep
%print_i = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @str, i32 0, i32 0), i32 %tmpgetfldld)
br label %match_end
match_end: ; preds = %case1, %entry
%r = alloca i32, align 4
store i32 0, i32* %r
%tmploadlocal = load i32, i32* %r
ret i32 %tmploadlocal
}
define i32 @main() {
entry:
%call = tail call i32 @"test.main$v"()
ret i32 %call
}
Теперь, как я сказал, это компилируется и запускается полностью, но по какой-то причине иногда печатается 1 вместо 3, что я совсем не понимаю . Я понятия не имею, как отлаживать код llvm ir, и применение прохода отладки с помощью opt приводит к неправильным исходным строкам (все с переменным смещением), что также приводит к NO SENSE (я использую llvm 8, но llvm 6.0.1 который я использовал раньше, показал те же результаты).
Затем, если я перемещу определение переменной r до выражения match, внезапно я получу сегфоут, положение которого я не могу точно определить из-за смещенных исходных линий ir, о которых я упоминал ранее.
Вот соответствующий код и ir для этого:
class Node {
fld value: int;
fld next: OptionalNode;
new(_value: int, _next: OptionalNode) {
value = _value;
next = _next;
}
}
enum OptionalNode {
val nil;
val some(Node);
}
fun main(): int {
var s: OptionalNode = OptionalNode.some(new Node(3, OptionalNode.nil));
var r: int = 0;
match s {
OptionalNode.some(n) => print n.value;
}
ret r;
}
; ModuleID = 'test.bc'
source_filename = "test"
%test.Node = type { i32, %test.OptionalNode }
%test.OptionalNode = type { i8, [8 x i8] }
%test.OptionalNode.nil = type { i8 }
%test.OptionalNode.some = type { i8, %test.Node* }
@str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
declare i32 @printf(i8*, ...)
define void @"test.Node.!ctor$[test.Node]i[test.OptionalNode]"(%test.Node* %this, i32 %_value, %test.OptionalNode %_next) {
entry:
%arg0 = alloca %test.Node*, align 8
store %test.Node* %this, %test.Node** %arg0
%arg1 = alloca i32, align 4
store i32 %_value, i32* %arg1
%arg2 = alloca %test.OptionalNode, align 16
store %test.OptionalNode %_next, %test.OptionalNode* %arg2
%ldarg1 = load i32, i32* %arg1
%tmpld_cls = load %test.Node*, %test.Node** %arg0
%tmpfld = getelementptr inbounds %test.Node, %test.Node* %tmpld_cls, i32 0, i32 0
store i32 %ldarg1, i32* %tmpfld
%ldarg2 = load %test.OptionalNode, %test.OptionalNode* %arg2
%tmpld_cls1 = load %test.Node*, %test.Node** %arg0
%tmpfld2 = getelementptr inbounds %test.Node, %test.Node* %tmpld_cls1, i32 0, i32 1
store %test.OptionalNode %ldarg2, %test.OptionalNode* %tmpfld2
ret void
}
define i32 @"test.main$v"() {
entry:
%s = alloca %test.OptionalNode, align 16
%enm = alloca %test.OptionalNode
%0 = bitcast %test.OptionalNode* %enm to %test.OptionalNode.nil*
%1 = getelementptr inbounds %test.OptionalNode.nil, %test.OptionalNode.nil* %0, i32 0, i32 0
store i8 0, i8* %1
%2 = load %test.OptionalNode, %test.OptionalNode* %enm
%tmpalloc = alloca %test.Node
call void @"test.Node.!ctor$[test.Node]i[test.OptionalNode]"(%test.Node* %tmpalloc, i32 3, %test.OptionalNode %2)
%enm1 = alloca %test.OptionalNode
%3 = bitcast %test.OptionalNode* %enm1 to %test.OptionalNode.some*
%4 = getelementptr inbounds %test.OptionalNode.some, %test.OptionalNode.some* %3, i32 0, i32 0
store i8 1, i8* %4
%5 = getelementptr inbounds %test.OptionalNode.some, %test.OptionalNode.some* %3, i32 0, i32 1
store %test.Node* %tmpalloc, %test.Node** %5
%6 = load %test.OptionalNode, %test.OptionalNode* %enm1
store %test.OptionalNode %6, %test.OptionalNode* %s
%r = alloca i32, align 4
store i32 0, i32* %r
%7 = getelementptr inbounds %test.OptionalNode, %test.OptionalNode* %s, i32 0, i32 0
%8 = load i8, i8* %7
switch i8 %8, label %match_end [
i8 1, label %case1
]
case1: ; preds = %entry
%n = alloca %test.Node*, align 8
%9 = bitcast %test.OptionalNode* %s to %test.OptionalNode.some*
%10 = getelementptr inbounds %test.OptionalNode.some, %test.OptionalNode.some* %9, i32 0, i32 1
%11 = load %test.Node*, %test.Node** %10
store %test.Node* %11, %test.Node** %n
%tmpld_cls = load %test.Node*, %test.Node** %n
%tmpgetfldgep = getelementptr inbounds %test.Node, %test.Node* %tmpld_cls, i32 0, i32 0
%tmpgetfldld = load i32, i32* %tmpgetfldgep
%print_i = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @str, i32 0, i32 0), i32 %tmpgetfldld)
br label %match_end
match_end: ; preds = %case1, %entry
%tmploadlocal = load i32, i32* %r
ret i32 %tmploadlocal
}
define i32 @main() {
entry:
%call = tail call i32 @"test.main$v"()
ret i32 %call
}
Я знаю, что такого рода вопросы действительно плохие, и я, вероятно, нарушаю некоторые правила, просто вставляя свой код сюда, но если кто-то пожертвует часть своего времени, чтобы помочь некоторым действительно расстроенным и близким к тому, чтобы бросить парня, я Буду очень благодарен.