LLVM: If/Then branching in tiny-go LLVM

113 Views Asked by At

I'm using tinygo's LLVM bindings for Go (don't know if this is relevant) and I'm trying to implement If/Then branching without the else block.

I've found this answer on stackoverflow: LLVM IRBuilder If-Then Codegen but it's using the C++ API and tinygo's bindings don't provide a way to "push_back" a block into a function.

I have this piece of code that I'm trying to compile:

func factorial(x: i8) -> i8 {

    if x == 0 {
        return 1;
    } 
    
    return x * factorial(x - 1);
}

I'm going to omit some stuff for simplicity, so here's the generated IR:

define i8 @factorial(i8 %x) {
entry:
  %RETURN_VALUE = alloca i8, align 1
  %0 = alloca i8, align 1
  store i8 %x, i8* %0, align 1
  %1 = load i8, i8* %0, align 1
  %2 = icmp eq i8 %1, 0
  br i1 %2, label %3, label %merge

3:                                                ; preds = %entry
  store i8 1, i8* %RETURN_VALUE, align 1
  br label %merge

merge:                                            ; preds = %3, %entry
  %4 = load i8, i8* %0, align 1
  %5 = load i8, i8* %0, align 1
  %6 = sub i8 %5, 1
  %7 = call i8 @factorial(i8 %6)
  %8 = mul i8 %4, %7
  store i8 %8, i8* %RETURN_VALUE, align 1
  %9 = load i8, i8* %RETURN_VALUE, align 1
  ret i8 %9
}

My approach is to have a variable of some sort and then if a return statement is encountered, just change it's value, so it can be returned once at the end of the function. This works perfectly fine with If/Then/Else branching, but I want my language to be imperative instead of functional and allow If/Then branching.

Also, I've tried compiling C code to LLVM IR (clang -S -emit-llvm x.c) and see what it looks like on the inside.

There are some dummy statements, because clang is always trying to make optimizations, but I want the IR to be as raw as possible.

int main() {

    int x = 8;
    if (x) {
        return 1;
    }

    x = 3;
    return 0;
}

this C code compiles to

define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 8, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = icmp ne i32 %3, 0
  br i1 %4, label %5, label %6

5:                                                ; preds = %0
  store i32 1, i32* %1, align 4
  br label %7

6:                                                ; preds = %0
  store i32 3, i32* %2, align 4
  store i32 0, i32* %1, align 4
  br label %7

7:                                                ; preds = %6, %5
  %8 = load i32, i32* %1, align 4
  ret i32 %8
}

I honestly have no idea how to implement this type of branching.

0

There are 0 best solutions below