From d80d88bc0fa2c92c83389a8cb2ad20acf07c3257 Mon Sep 17 00:00:00 2001 From: Ben Shi Date: Mon, 28 Nov 2022 11:13:37 +0800 Subject: [PATCH] llvm: implement support of closure functions. --- _examples/llvm/internal_function.wa | 22 ++++++++--- internal/backends/compiler_llvm/compile.go | 18 +++++++-- .../compiler_llvm/compile_function.go | 10 ++++- .../backends/compiler_llvm/compile_value.go | 38 +++++++++++++++++-- 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/_examples/llvm/internal_function.wa b/_examples/llvm/internal_function.wa index d9e80e2..dc857c0 100644 --- a/_examples/llvm/internal_function.wa +++ b/_examples/llvm/internal_function.wa @@ -1,18 +1,30 @@ # Test the llvm backend. # Test anonymous functions and closure functions. +type pair struct { + i :f32 + j :f32 +} + fn main() { print("Hello, ") fn() { println("World!") }() - var i: int - show := fn() { - println("i = ", i) + var i: int = 31 + var j: [4]f32 = [4]f32{1, 2.2, 5.5, 9.8} + var k: pair = pair{3.14, 2.718} + show := fn(q: int) { + println(i, " + ", q, " = ", i+q) + println("{", j[0], ", ", j[1], ", ", j[2], ", ", j[3], "}") + println("{", k.i, ", ", k.j, "}") } - for i = 0; i < 10; i++ { - show() + for i := int(0); i < 4; i++ { + j[i] += 1.0 + k.i += 0.1 + k.j -= 0.1 + show(i) } } diff --git a/internal/backends/compiler_llvm/compile.go b/internal/backends/compiler_llvm/compile.go index 3fb3c77..cf08328 100644 --- a/internal/backends/compiler_llvm/compile.go +++ b/internal/backends/compiler_llvm/compile.go @@ -16,12 +16,22 @@ type FmtStr struct { size int } +type Argument struct { + AType string + AName string +} + +type InnerFunc struct { + fn *ssa.Function + args []Argument +} + type Compiler struct { target string output strings.Builder debug bool fmts []FmtStr - anofn []*ssa.Function + anofn []InnerFunc } func New(target string, debug bool) *Compiler { @@ -138,18 +148,18 @@ func (p *Compiler) compilePackage(pkg *ssa.Package) error { // Generate LLVM-IR for each global function. for _, v := range fns { - if err := p.compileFunction(v); err != nil { + if err := p.compileFunction(v, []Argument{}); err != nil { return err } } // Generate LLVM-IR for each internal function. for _, v := range p.anofn { - if err := p.compileFunction(v); err != nil { + if err := p.compileFunction(v.fn, v.args); err != nil { return err } } - p.anofn = []*ssa.Function{} + p.anofn = []InnerFunc{} return nil } diff --git a/internal/backends/compiler_llvm/compile_function.go b/internal/backends/compiler_llvm/compile_function.go index c7cb471..aafbdc6 100644 --- a/internal/backends/compiler_llvm/compile_function.go +++ b/internal/backends/compiler_llvm/compile_function.go @@ -11,7 +11,7 @@ import ( "github.com/wa-lang/wa/internal/types" ) -func (p *Compiler) compileFunction(fn *ssa.Function) error { +func (p *Compiler) compileFunction(fn *ssa.Function, extraArgs []Argument) error { if isTargetBuiltin(fn.LinkName(), p.target) || isTargetBuiltin(fn.Name(), p.target) { return nil } @@ -82,6 +82,14 @@ func (p *Compiler) compileFunction(fn *ssa.Function) error { p.output.WriteString(", ") } } + // Emit binded values as extra arguments for closure functions. + for _, v := range extraArgs { + p.output.WriteString(", ") + p.output.WriteString(v.AType) + p.output.WriteString(" ") + p.output.WriteString(v.AName) + } + // Finish emitting function header. if len(fn.Blocks) == 0 { p.output.WriteString(")\n\n") return nil diff --git a/internal/backends/compiler_llvm/compile_value.go b/internal/backends/compiler_llvm/compile_value.go index 36f20ec..390aaf1 100644 --- a/internal/backends/compiler_llvm/compile_value.go +++ b/internal/backends/compiler_llvm/compile_value.go @@ -114,6 +114,10 @@ func (p *Compiler) compileValue(val ssa.Value) error { p.output.WriteString(fmt.Sprintf("%d", val.Index)) p.output.WriteString("\n") + case *ssa.MakeClosure: + // We postpone the process of closure functions to the fist call of them. + break + default: p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n") // panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") @@ -359,7 +363,7 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { func (p *Compiler) compileCall(val *ssa.Call) error { switch val.Call.Value.(type) { - case *ssa.Function: + case *ssa.Function, *ssa.MakeClosure: // Special process for float32 constants. paf32 := map[int]string{} for i, v := range val.Call.Args { @@ -389,16 +393,42 @@ func (p *Compiler) compileCall(val *ssa.Call) error { callee := val.Call.StaticCallee() // This callee is an internal function, whose body will be genereated later. if callee.Parent() != nil { - p.anofn = append(p.anofn, callee) + found := false + for _, f := range p.anofn { + if f.fn == callee { + found = true + } + } + if !found { + inner := InnerFunc{callee, []Argument{}} + // Collect all binded values for closure functions, then emit them as implicit arguments. + if cl, ok := val.Call.Value.(*ssa.MakeClosure); ok { + for _, v := range cl.Bindings { + if al, ok := v.(*ssa.Alloc); ok { + arg := Argument{getTypeStr(v.Type(), p.target), "%" + al.Comment} + inner.args = append(inner.args, arg) + } + } + } + p.anofn = append(p.anofn, inner) + } } + // Emit link name for external functions. if len(callee.LinkName()) > 0 { p.output.WriteString(callee.LinkName()) } else { p.output.WriteString(getNormalName(callee.Pkg.Pkg.Path() + "." + callee.Name())) } p.output.WriteString("(") + // Collect all binded values for closure functions, then pass them as implicit parameters. + params := val.Call.Args[0:] + if cl, ok := val.Call.Value.(*ssa.MakeClosure); ok { + for _, v := range cl.Bindings { + params = append(params, v) + } + } // Emit parameters. - for i, v := range val.Call.Args { + for i, v := range params { ty := getRealType(v.Type()) tyStr := getTypeStr(ty, p.target) switch ty.(type) { @@ -414,7 +444,7 @@ func (p *Compiler) compileCall(val *ssa.Call) error { } else { p.output.WriteString(getValueStr(v)) } - if i < len(val.Call.Args)-1 { + if i < len(params)-1 { p.output.WriteString(", ") } } -- GitLab