From 58b853bbef075a0ae947b6fa4170d7e4248fcd88 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 1 Sep 2018 17:09:56 +0200 Subject: [PATCH] Defer for trivial cases --- README.markdown | 3 ++- compiler.go | 34 ++++++++++++++++++++++++++++++++++ src/examples/hello/hello.go | 13 +++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index f6bbd43d..6d75ab04 100644 --- a/README.markdown +++ b/README.markdown @@ -47,12 +47,13 @@ Currently supported features: features) * slices (partially) * maps (very rough, unfinished) + * defer (only in trivial cases) Not yet supported: * complex numbers * garbage collection - * defer + * recover * closures * channels * introspection (if it ever gets implemented) diff --git a/compiler.go b/compiler.go index a232f0de..4db2aed8 100644 --- a/compiler.go +++ b/compiler.go @@ -61,6 +61,12 @@ type Frame struct { taskHandle llvm.Value cleanupBlock llvm.BasicBlock suspendBlock llvm.BasicBlock + deferred []*Defer +} + +type Defer struct { + *ssa.Defer + Args []llvm.Value } type Phi struct { @@ -1081,6 +1087,22 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { return err case *ssa.DebugRef: return nil // ignore + case *ssa.Defer: + if instr.Block() == instr.Parent().Blocks[0] { + // Easy: evaluate the arguments now and run it at the end. + args := make([]llvm.Value, len(instr.Call.Args)) + for i, arg := range instr.Call.Args { + val, err := c.parseExpr(frame, arg) + if err != nil { + return err + } + args[i] = val + } + frame.deferred = append(frame.deferred, &Defer{instr, args}) + return nil + } else { + return errors.New("todo: defer in non-entry block") + } case *ssa.Go: if instr.Common().Method != nil { return errors.New("todo: go on method receiver") @@ -1203,6 +1225,18 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { return nil } } + case *ssa.RunDefers: + // Execute all deferred functions from the entry block, in reverse + // order. + for i := len(frame.deferred) - 1; i >= 0; i-- { + deferred := frame.deferred[i] + callee := deferred.Call.StaticCallee() + if callee == nil { + return errors.New("todo: non-static deferred functions") + } + c.builder.CreateCall(c.ir.GetFunction(callee).llvmFn, deferred.Args, "") + } + return nil case *ssa.Store: llvmAddr, err := c.parseExpr(frame, instr.Addr) if err == cgoWrapperError { diff --git a/src/examples/hello/hello.go b/src/examples/hello/hello.go index 592b239e..3362dd7f 100644 --- a/src/examples/hello/hello.go +++ b/src/examples/hello/hello.go @@ -48,6 +48,7 @@ func main() { println("Stringer.String():", s.String()) runFunc(hello, 5) // must be indirect to avoid obvious inlining + testDefer() // test library functions println("lower to upper char:", 'h', "->", unicode.ToUpper('h')) @@ -57,6 +58,18 @@ func runFunc(f func(int), arg int) { f(arg) } +func testDefer() { + i := 1 + defer deferred("...run as defer", i) + i += 1 + defer deferred("...run as defer", i) + println("deferring...") +} + +func deferred(msg string, i int) { + println(msg, i) +} + func readMap(m map[string]int, key string) { println("map length:", len(m)) println("map read:", key, "=", m[key])