From d08ff64d1d119f3c94fe61df3e219c93a16f6e03 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 11 Apr 2018 20:41:09 +0200 Subject: [PATCH] Move string printing to runtime --- Makefile | 15 ++++++--- runtime/runtime.c | 30 ++++++++++++++++++ runtime/runtime.h | 12 +++++++ tgo.go | 81 +++++++++++++++++++++++++++++++---------------- 4 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 runtime/runtime.c create mode 100644 runtime/runtime.h diff --git a/Makefile b/Makefile index 031a1fd2..e5397dd3 100644 --- a/Makefile +++ b/Makefile @@ -3,19 +3,24 @@ all: tgo tgo: build/tgo test: build/hello.o -.PHONY: all tgo test test-run clean +CFLAGS = -Wall -Werror -O2 -g -flto + +.PHONY: all tgo test run-test clean build/tgo: *.go @mkdir -p build @go build -o build/tgo -i . build/hello.o: build/tgo hello/hello.go - @./build/tgo -printir -target x86_64-pc-linux-gnu -o build/hello.o hello/hello.go + @./build/tgo -printir -o build/hello.o hello/hello.go -build/hello: build/hello.o - @clang -o build/hello build/hello.o +build/runtime.o: runtime/*.c runtime/*.h + clang $(CFLAGS) -c -o $@ runtime/*.c -test-run: build/hello +build/hello: build/hello.o build/runtime.o + @clang $(CFLAGS) -o $@ $^ + +run-test: build/hello @./build/hello clean: diff --git a/runtime/runtime.c b/runtime/runtime.c new file mode 100644 index 00000000..23745a60 --- /dev/null +++ b/runtime/runtime.c @@ -0,0 +1,30 @@ + +#include +#include +#include +#include "runtime.h" + +void __go_printstring(char *str) { + write(STDOUT_FILENO, str, strlen(str)); +} + +void __go_printspace() { + write(STDOUT_FILENO, " ", 1); +} + +void __go_printnl() { + write(STDOUT_FILENO, "\n", 1); +} + +void go_main() __asm__("main.main"); + +void __go_runtime_main() { + go_main(); +} + +__attribute__((weak)) +int main() { + __go_runtime_main(); + + return 0; +} diff --git a/runtime/runtime.h b/runtime/runtime.h new file mode 100644 index 00000000..03f917df --- /dev/null +++ b/runtime/runtime.h @@ -0,0 +1,12 @@ + +#pragma once + +#include + +typedef struct { + uint32_t length; // TODO: size_t + uint8_t *data; +} string_t; + +void __go_printstring(char *str); +void __go_printnl(); diff --git a/tgo.go b/tgo.go index 11326867..0705b50c 100644 --- a/tgo.go +++ b/tgo.go @@ -23,11 +23,13 @@ func init() { } type Compiler struct { - mod llvm.Module - ctx llvm.Context - builder llvm.Builder - machine llvm.TargetMachine - putsFunc llvm.Value + mod llvm.Module + ctx llvm.Context + builder llvm.Builder + machine llvm.TargetMachine + printstringFunc llvm.Value + printspaceFunc llvm.Value + printnlFunc llvm.Value } func NewCompiler(path, triplet string) (*Compiler, error) { @@ -43,8 +45,12 @@ func NewCompiler(path, triplet string) (*Compiler, error) { c.ctx = c.mod.Context() c.builder = c.ctx.NewBuilder() - putsType := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{llvm.PointerType(llvm.Int8Type(), 0)}, false) - c.putsFunc = llvm.AddFunction(c.mod, "puts", putsType) + printstringType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.PointerType(llvm.Int8Type(), 0)}, false) + c.printstringFunc = llvm.AddFunction(c.mod, "__go_printstring", printstringType) + printspaceType := llvm.FunctionType(llvm.VoidType(), nil, false) + c.printspaceFunc = llvm.AddFunction(c.mod, "__go_printspace", printspaceType) + printnlType := llvm.FunctionType(llvm.VoidType(), nil, false) + c.printnlFunc = llvm.AddFunction(c.mod, "__go_printnl", printnlType) return c, nil } @@ -66,7 +72,7 @@ func (c *Compiler) Parse(path string) error { } fmt.Println("package:", pkgInfo.Pkg.Name()) for _, file := range pkgInfo.Files { - err := c.parseFile(file) + err := c.parseFile(pkgInfo.Pkg.Name(), file) if err != nil { return err } @@ -75,16 +81,11 @@ func (c *Compiler) Parse(path string) error { return nil } -func (c *Compiler) IR() string { - return c.mod.String() -} - - -func (c *Compiler) parseFile(file *ast.File) error { +func (c *Compiler) parseFile(pkgName string, file *ast.File) error { for _, decl := range file.Decls { switch v := decl.(type) { case *ast.FuncDecl: - err := c.parseFunc(v) + err := c.parseFunc(pkgName, v) if err != nil { return err } @@ -96,11 +97,17 @@ func (c *Compiler) parseFile(file *ast.File) error { return nil } -func (c *Compiler) parseFunc(f *ast.FuncDecl) error { +func (c *Compiler) parseFunc(pkgName string, f *ast.FuncDecl) error { fmt.Println("func:", f.Name) - fnType := llvm.FunctionType(llvm.Int32Type(), nil, false) - fn := llvm.AddFunction(c.mod, f.Name.Name, fnType) + var fnType llvm.Type + if f.Type.Results == nil { + fnType = llvm.FunctionType(llvm.VoidType(), nil, false) + } else { + return errors.New("todo: return values") + } + + fn := llvm.AddFunction(c.mod, pkgName + "." + f.Name.Name, fnType) start := c.ctx.AddBasicBlock(fn, "start") c.builder.SetInsertPointAtEnd(start) @@ -112,7 +119,11 @@ func (c *Compiler) parseFunc(f *ast.FuncDecl) error { } } - c.builder.CreateRet(llvm.ConstInt(llvm.Int32Type(), 0, false)) + if f.Type.Results == nil { + c.builder.CreateRetVoid() + //} else if len(f.Type.Results.List) == 1 { + // c.builder.CreateRet(llvm.ConstInt(llvm.Int32Type(), 0, false)) + } return nil } @@ -132,26 +143,32 @@ func (c *Compiler) parseStmt(stmt ast.Node) error { func (c *Compiler) parseExpr(expr ast.Expr) error { switch v := expr.(type) { case *ast.CallExpr: - values := []llvm.Value{} - zero := llvm.ConstInt(llvm.Int32Type(), 0, false) name := v.Fun.(*ast.Ident).Name fmt.Printf(" call: %s\n", name) - if name != "println" { - return errors.New("implement anything other than println()") + printnl := false + if name == "println" { + printnl = true + } else if name == "print" { + } else { + return errors.New("todo: call anything other than println()") } - for _, arg := range v.Args { + for i, arg := range v.Args { + if i >= 1 { + c.builder.CreateCall(c.printspaceFunc, nil, "") + } switch arg := arg.(type) { case *ast.BasicLit: fmt.Printf(" arg: %s\n", arg.Value) val := constant.MakeFromLiteral(arg.Value, arg.Kind, 0) switch arg.Kind { case token.STRING: - msg := c.builder.CreateGlobalString(constant.StringVal(val) + "\x00", "") - msgCast := c.builder.CreateGEP(msg, []llvm.Value{zero, zero}, "") - values = append(values, msgCast) + str := constant.StringVal(val) + strObj := c.builder.CreateGlobalString(str + "\x00", "") + msgCast := c.builder.CreateGEP(strObj, []llvm.Value{zero, zero}, "") + c.builder.CreateCall(c.printstringFunc, []llvm.Value{msgCast}, "") default: return errors.New("todo: print anything other than strings") } @@ -159,13 +176,20 @@ func (c *Compiler) parseExpr(expr ast.Expr) error { return errors.New("unknown arg type") } } - c.builder.CreateCall(c.putsFunc, values, "") + if printnl { + c.builder.CreateCall(c.printnlFunc, nil, "") + } default: return errors.New("unknown expr") } return nil } +// IR returns the whole IR as a human-readable string. +func (c *Compiler) IR() string { + return c.mod.String() +} + func (c *Compiler) Verify() error { return llvm.VerifyModule(c.mod, llvm.PrintMessageAction) } @@ -201,6 +225,7 @@ func (c *Compiler) EmitObject(path string) error { return nil } +// Helper function for Compiler object. func Compile(inpath, outpath, target string, printIR bool) error { c, err := NewCompiler(inpath, target) if err != nil {