Skip to content

andybalholm/leaven

Folders and files

NameName
Last commit message
Last commit date
Jan 28, 2022
Jan 28, 2022
Jan 28, 2022
Aug 3, 2019
Jan 18, 2022
Jan 27, 2022
Apr 10, 2022
Apr 10, 2022
Apr 10, 2022
Jan 28, 2022
Jan 28, 2022
Apr 10, 2022
Jan 23, 2022
Jan 28, 2022
Jan 28, 2022

Repository files navigation

Leaven: Compile LLVM IR to Go

Leaven translates LLVM intermediate representation to Go. In theory, it should be able to transpile any language that has an LLVM-based compiler to Go. But so far I’ve only used it for C.

Each LLVM instruction is translated to an equivalent statement in Go. This produces very verbose code; if you are looking for a tool that will convert a C codebase into maintainable Go, Leaven isn’t it.

But it does allow you to call C code from Go without using CGo. And I am hoping that it can produce a working Go translation of a program, which will be a good starting point for incrementally re-translating it (probably by hand) into idiomatic Go.

Warning

This software is incomplete and experimental. It does not support nearly all LLVM instructions.

The transpiler at github.com/andybalholm/c2go produces much better results (but it is not as automatic).

Usage Example

(Translating strcmp from musl libc.)

$ cat strcmp.c
#include <string.h>

int strcmp(const char *l, const char *r)
{
	for (; *l==*r && *l; l++, r++);
	return *(unsigned char *)l - *(unsigned char *)r;
}
$ clang -S -emit-llvm -fno-discard-value-names strcmp.c
$ leaven strcmp.ll
$ goimports -w strcmp.go
$ cat strcmp.go
package main

import "unsafe"

func strcmp(l *byte, r *byte) int32 {
	var l_addr, r_addr **byte
	var v0, v2, v4, v7, incdec_ptr, v8, incdec_ptr4, v9, v11 *byte
	var cmp, tobool, v6 bool
	var v1, v3, v5, v10, v12 byte
	var conv, conv1, conv3, conv5, conv6, sub int32

	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = l_addr, r_addr, v0, v1, conv, v2, v3, conv1, cmp, v4, v5, conv3, tobool, v6, v7, incdec_ptr, v8, incdec_ptr4, v9, v10, conv5, v11, v12, conv6, sub

	l_addr = new(*byte)
	r_addr = new(*byte)
	*l_addr = l
	*r_addr = r
	goto for_cond

for_cond:
	v0 = *l_addr
	v1 = *v0
	conv = int32(int8(v1))
	v2 = *r_addr
	v3 = *v2
	conv1 = int32(int8(v3))
	cmp = conv == conv1
	if cmp {
		goto land_rhs
	} else {
		v6 = false
		goto land_end
	}

land_rhs:
	v4 = *l_addr
	v5 = *v4
	conv3 = int32(int8(v5))
	tobool = conv3 != 0
	v6 = tobool
	goto land_end

land_end:
	if v6 {
		goto for_body
	} else {
		goto for_end
	}

for_body:
	goto for_inc

for_inc:
	v7 = *l_addr
	incdec_ptr = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(v7)) + 1*unsafe.Sizeof(*(*byte)(nil))))
	*l_addr = incdec_ptr
	v8 = *r_addr
	incdec_ptr4 = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(v8)) + 1*unsafe.Sizeof(*(*byte)(nil))))
	*r_addr = incdec_ptr4
	goto for_cond

for_end:
	v9 = *l_addr
	v10 = *v9
	conv5 = int32(uint32(v10))
	v11 = *r_addr
	v12 = *v11
	conv6 = int32(uint32(v12))
	sub = conv5 - conv6
	return sub
}

About

translate LLVM IR to Go

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published