From d620f0d1885b24f69c938820725db00c0014e332 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 29 Aug 2018 19:42:22 +0200 Subject: [PATCH] Implement multiple return values from functions Use structs in LLVM as it appears LLVM has no support for multiple return values (I should look into how Rust does it...). --- compiler.go | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/compiler.go b/compiler.go index 6d4009ed..3ea277b6 100644 --- a/compiler.go +++ b/compiler.go @@ -497,7 +497,16 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) { return llvm.Type{}, err } } else { - return llvm.Type{}, errors.New("todo: multiple return values in function pointer") + // Multiple return values. Put them together in a struct. + members := make([]llvm.Type, typ.Results().Len()) + for i := 0; i < typ.Results().Len(); i++ { + returnType, err := c.getLLVMType(typ.Results().At(i).Type()) + if err != nil { + return llvm.Type{}, err + } + members[i] = returnType + } + returnType = llvm.StructType(members, false) } // param values var paramTypes []llvm.Type @@ -654,7 +663,15 @@ func (c *Compiler) parseFuncDecl(f *Function) (*Frame, error) { return nil, err } } else { - return nil, errors.New("todo: return values") + results := make([]llvm.Type, 0, f.fn.Signature.Results().Len()) + for i := 0; i < f.fn.Signature.Results().Len(); i++ { + typ, err := c.getLLVMType(f.fn.Signature.Results().At(i).Type()) + if err != nil { + return nil, err + } + results = append(results, typ) + } + retType = llvm.StructType(results, false) } var paramTypes []llvm.Type @@ -1134,7 +1151,20 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { c.builder.CreateRet(val) return nil } else { - return errors.New("todo: return value") + // Multiple return values. Put them all in a struct. + retVal, err := getZeroValue(frame.fn.llvmFn.Type().ElementType().ReturnType()) + if err != nil { + return err + } + for i, result := range instr.Results { + val, err := c.parseExpr(frame, result) + if err != nil { + return err + } + retVal = c.builder.CreateInsertValue(retVal, val, i, "") + } + c.builder.CreateRet(retVal) + return nil } } case *ssa.Store: