From 18b16fc151a839bcd88307cbfb38eaaf4ad44c3d Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 22 Dec 2018 17:11:39 +0100 Subject: [PATCH] compiler: run some optimizations after interface lowering By running these interprocedural optimizations after interface lowering, in particular the heap-to-stack transformation pass, interfaces can be zero cost in some more cases. For example, say you have the following interface: type Writer interface { Write([]byte) (int, error) } and you do something with it: func foo(w io.Writer) { w.Write([]byte("foo")) } this commit enables escape analysis across interface boundaries, which means that the Write call does not cause an allocation if all implementations of io.Writer do not let the slice escape. This enables broader uses of interfaces, as they are now a zero-cost abstraction in more cases. --- compiler/optimizer.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/optimizer.go b/compiler/optimizer.go index cf4b95801..b78a4fb86 100644 --- a/compiler/optimizer.go +++ b/compiler/optimizer.go @@ -43,6 +43,15 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro c.OptimizeStringToBytes() c.OptimizeAllocs() c.LowerInterfaces() + + // After interfaces are lowered, there are many more opportunities for + // interprocedural optimizations. To get them to work, function + // attributes have to be updated first. + goPasses.Run(c.mod) + + // Run TinyGo-specific interprocedural optimizations. + c.OptimizeAllocs() + c.OptimizeStringToBytes() } else { // Must be run at any optimization level. c.LowerInterfaces()