go0

command module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 21, 2023 License: BSD-3-Clause Imports: 14 Imported by: 0

README

go0

Go0 is a [self] educational toy Go compiler for a minimalistic subset of Go. It demonstrates how to use the modernc.org/libqbe compiler back end.

Installation

$ go install modernc.org/go0@latest

Documentation

See pkg.go.dev/modernc.org/go0

Documentation

Overview

Go0 is a [self] educational toy Go compiler for a minimalistic subset of Go. It demonstrates how to use the modernc.org/libqbe compiler back end.

Supported targets

Go0 builds, runs and was tested to correctly produce native executable files on

GOOS/GOARCH
-----------
darwin/amd64
darwin/arm64
freebsd/amd64
freebsd/arm64
linux/amd64
linux/arm64
linux/riscv64
netbsd/amd64
openbsd/amd64

The input

This is a valid, self-contained Go program:

package main

func fib(a int) int {
	if a < 2 {
		return a
	}
	return fib(a-1) + fib(a-2)
}

func main() {
	println(fib(42))
}

Go0 can handle the code above and nothing else.

What Go0 does

When executed, the "compiler" creates a package in a temporary directory with import path "example.com/fib" in its go.mod file, containing one Go file, fib.go with the input program as seen above.

It then uses golang.org/x/tools/go/packages to load the package and the golang.org/x/tools/go/ssa{,/ssautil} packages to construct its SSA form.

Next step is to generate QBE IL from the SSA. Then we use modernc.org/libqbe to generate fib.s, its assembler version.

We can use the system assembler (like GNU as) and linker to produce the executable. However, it is easier to just hand over the fib.s file to the system C compiler. It'll do the same for us in one step. It also takes care of adding proper startup code etc.

Then Go0 shows the size of the executable binary file, its type via file(1) and finally the output the executable produces along with time used to compute the result.

The compiler SLOC

~/src/modernc.org/go0$ gocloc main.go
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Go                               1             31              3            192
-------------------------------------------------------------------------------
TOTAL                            1             31              3            192
-------------------------------------------------------------------------------
~/src/modernc.org/go0$

Example session

This output was produced on a Linux/Amd64 machine.

~/src/modernc.org/go0$ go0
---- Go
package main

func fib(a int) int {
	if a < 2 {
		return a
	}
	return fib(a-1) + fib(a-2)
}

func main() {
	println(fib(42))
}

---- SSA
# Name: example.com/fib.init
# Package: example.com/fib
# Synthetic: package initializer
func init():
0:                                                                entry P:0 S:2
	t0 = *init$guard                                                   bool
	if t0 goto 2 else 1
1:                                                           init.start P:1 S:1
	*init$guard = true:bool
	jump 2
2:                                                            init.done P:2 S:0
	return

# Name: example.com/fib.fib
# Package: example.com/fib
# Location: /tmp/go0-1743633831/fib.go:3:6
func fib(a int) int:
0:                                                                entry P:0 S:2
	t0 = a < 2:int                                                     bool
	if t0 goto 1 else 2
1:                                                              if.then P:1 S:0
	return a
2:                                                              if.done P:1 S:0
	t1 = a - 1:int                                                      int
	t2 = fib(t1)                                                        int
	t3 = a - 2:int                                                      int
	t4 = fib(t3)                                                        int
	t5 = t2 + t4                                                        int
	return t5

# Name: example.com/fib.main
# Package: example.com/fib
# Location: /tmp/go0-1743633831/fib.go:10:6
func main():
0:                                                                entry P:0 S:0
	t0 = fib(42:int)                                                    int
	t1 = println(t0)                                                     ()
	return

---- QBE
function l $fib(l %a) {
@.0
	%t0 =w csltl %a, 2
	jnz %t0, @.1, @.2
@.1
	ret %a
@.2
	%t1 =l sub %a, 1
	%t2 =l call $fib(l %t1)
	%t3 =l sub %a, 2
	%t4 =l call $fib(l %t3)
	%t5 =l add %t2, %t4
	ret %t5
}

export function w $main() {
@.0
	%t0 =l call $fib(l 42)
	call $printf(l $fmt, ..., l %t0)
	ret 0
}

data $fmt = { b "%d\n", b 0 }

---- ASM
.text
fib:
	pushq %rbp
	movq %rsp, %rbp
	subq $8, %rsp
	pushq %rbx
	movq %rdi, %rbx
	cmpq $2, %rbx
	jl .Lbb2
	movq %rbx, %rdi
	subq $1, %rdi
	callq fib
	xchgq %rax, %rbx
	movq %rax, %rdi
	subq $2, %rdi
	callq fib
	addq %rbx, %rax
	jmp .Lbb3
.Lbb2:
	movq %rbx, %rax
.Lbb3:
	popq %rbx
	leave
	ret
.type fib, @function
.size fib, .-fib
/* end function fib */

.text
.globl main
main:
	pushq %rbp
	movq %rsp, %rbp
	movl $42, %edi
	callq fib
	movq %rax, %rsi
	leaq fmt(%rip), %rdi
	movl $0, %eax
	callq printf
	movl $0, %eax
	leave
	ret
.type main, @function
.size main, .-main
/* end function main */

.data
.balign 8
fmt:
	.ascii "%d\n"
	.byte 0
/* end data */

.section .note.GNU-stack,"",@progbits

---- Outputs
-rwxr-xr-x 1 jnml jnml 16024 Nov 17 15:07 /tmp/go0-1743633831/fib
/tmp/go0-1743633831/fib: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=058411db3a5de732ea39648339e88d636aef0e2a, for GNU/Linux 3.2.0, not stripped
267914296
1.94user 0.00system 0:01.94elapsed 100%CPU (0avgtext+0avgdata 1408maxresident)k
0inputs+0outputs (0major+92minor)pagefaults 0swaps
~/src/modernc.org/go0$

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL