k3v
k3v

Reputation: 119

LLVM IR - Can someone explain this behavior?

I'm trying to build a compiler for my language at the moment. In my language, I want to have implicit pointer usage for objects/structs just like in Java. In the program below, I am testing out this feature. However, the program does not run as I had expected. I do not expect you guys to read through my entire compiler code because that would be a waste of time. Instead I was hoping I could explain what I intended for the program to do and you guys could spot in the llvm ir what went wrong. That way, I can adjust the compiler to generate proper llvm ir.


Flow:
[Function] Main - [Return: Int] {
-> Allocates space for structure of one i32
-> Calls createObj function and stores the returning value inside previous allocated space
-> Returns the i32 of the structure
}

[Function] createObj - [Return: struct { i32 }] {
-> Allocates space for structure of one i32
-> Calls Object function on this space (pointer really)
-> Returns this space (pointer really)
}

[Function] Object - [Return: void] {
-> Stores the i32 value of 5 inside of the struct pointer argument
}


The program is that main keeps returning some random number instead of 5. One such number is 159383856. I'm guessing that this is the decimal representation of a pointer address, but I'm not sure why it is printing out the pointer address.


; ModuleID = 'main'

%Object = type { i32 }

define i32 @main() {
entry:
  %0 = call %Object* @createObj()
  %o = alloca %Object*
  store %Object* %0, %Object** %o
  %1 = load %Object** %o
  %2 = getelementptr inbounds %Object* %1, i32 0, i32 0
  %3 = load i32* %2
  ret i32 %3
}

define %Object* @createObj() {
entry:
  %0 = alloca %Object
  call void @-Object(%Object* %0)
  %o = alloca %Object*
  store %Object* %0, %Object** %o
  %1 = load %Object** %o
  ret %Object* %1
}

define void @-Object(%Object* %this) {
entry:
  %0 = getelementptr inbounds %Object* %this, i32 0, i32 0
  store i32 5, i32* %0
  ret void
}

This llvm ir is generated from this syntax.

func () > main > (int) {
    Object o = createObj();

    return o.id;
}

// Create an object and returns it
func () > createObj > (Object) { 
    Object o = make Object < ();

    return o;
}

// Object decl
tmpl Object {
    int id; // Property

    // This is run every time an object is created.
    constructor < () {
        this.id = 5;
    }
}

Upvotes: 1

Views: 452

Answers (1)

Colin LeMahieu
Colin LeMahieu

Reputation: 618

It seems like in createObj you're returning a pointer to a stack variable which will no longer be valid after function return.

If you're doing implicit object pointers like Java at minimum you're going to need a call to a heap allocation like malloc which I don't think you have.

Upvotes: 4

Related Questions