diff --git a/cl/_testrt/result/in.go b/cl/_testrt/result/in.go new file mode 100644 index 00000000..e4e9ec7d --- /dev/null +++ b/cl/_testrt/result/in.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/goplus/llgo/internal/runtime/c" +) + +func main() { + fn := func() func(int, int) int { + return func(x, y int) int { + return x + y + } + }() + c.Printf(c.Str("%d\n"), fn(100, 200)) + c.Printf(c.Str("%d\n"), add()(100, 200)) + fn, n := add2() + c.Printf(c.Str("%d %d\n"), add()(100, 200), n) +} + +func add() func(int, int) int { + return func(x, y int) int { + return x + y + } +} + +func add2() (func(int, int) int, int) { + return func(x, y int) int { + return x + y + }, 1 +} diff --git a/cl/_testrt/result/out.ll b/cl/_testrt/result/out.ll new file mode 100644 index 00000000..c3494581 --- /dev/null +++ b/cl/_testrt/result/out.ll @@ -0,0 +1,120 @@ +; ModuleID = 'main' +source_filename = "main" + +@"main.init$guard" = global ptr null +@0 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 +@2 = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1 + +define { ptr, ptr } @main.add() { +_llgo_0: + %0 = alloca { ptr, ptr }, align 8 + %1 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 0 + store ptr @"__llgo_stub.main.add$1", ptr %1, align 8 + %2 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 1 + store ptr null, ptr %2, align 8 + %3 = load { ptr, ptr }, ptr %0, align 8 + ret { ptr, ptr } %3 +} + +define { { ptr, ptr }, i64 } @main.add2() { +_llgo_0: + %0 = alloca { ptr, ptr }, align 8 + %1 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 0 + store ptr @"__llgo_stub.main.add2$1", ptr %1, align 8 + %2 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 1 + store ptr null, ptr %2, align 8 + %3 = load { ptr, ptr }, ptr %0, align 8 + %mrv = insertvalue { { ptr, ptr }, i64 } poison, { ptr, ptr } %3, 0 + %mrv1 = insertvalue { { ptr, ptr }, i64 } %mrv, i64 1, 1 + ret { { ptr, ptr }, i64 } %mrv1 +} + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define void @main() { +_llgo_0: + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %0 = call { ptr, ptr } @"main.main$1"() + %1 = extractvalue { ptr, ptr } %0, 1 + %2 = extractvalue { ptr, ptr } %0, 0 + %3 = call i64 %2(ptr %1, i64 100, i64 200) + %4 = call i32 (ptr, ...) @printf(ptr @0, i64 %3) + %5 = call { ptr, ptr } @main.add() + %6 = extractvalue { ptr, ptr } %5, 1 + %7 = extractvalue { ptr, ptr } %5, 0 + %8 = call i64 %7(ptr %6, i64 100, i64 200) + %9 = call i32 (ptr, ...) @printf(ptr @1, i64 %8) + %10 = call { { ptr, ptr }, i64 } @main.add2() + %11 = extractvalue { { ptr, ptr }, i64 } %10, 0 + %12 = extractvalue { { ptr, ptr }, i64 } %10, 1 + %13 = call { ptr, ptr } @main.add() + %14 = extractvalue { ptr, ptr } %13, 1 + %15 = extractvalue { ptr, ptr } %13, 0 + %16 = call i64 %15(ptr %14, i64 100, i64 200) + %17 = call i32 (ptr, ...) @printf(ptr @2, i64 %16, i64 %12) + ret void +} + +define i64 @"main.add$1"(i64 %0, i64 %1) { +_llgo_0: + %2 = add i64 %0, %1 + ret i64 %2 +} + +define linkonce i64 @"__llgo_stub.main.add$1"(ptr %0, i64 %1, i64 %2) { +_llgo_0: + %3 = tail call i64 @"main.add$1"(i64 %1, i64 %2) + ret i64 %3 +} + +define i64 @"main.add2$1"(i64 %0, i64 %1) { +_llgo_0: + %2 = add i64 %0, %1 + ret i64 %2 +} + +define linkonce i64 @"__llgo_stub.main.add2$1"(ptr %0, i64 %1, i64 %2) { +_llgo_0: + %3 = tail call i64 @"main.add2$1"(i64 %1, i64 %2) + ret i64 %3 +} + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +define { ptr, ptr } @"main.main$1"() { +_llgo_0: + %0 = alloca { ptr, ptr }, align 8 + %1 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 0 + store ptr @"__llgo_stub.main.main$1$1", ptr %1, align 8 + %2 = getelementptr inbounds { ptr, ptr }, ptr %0, i32 0, i32 1 + store ptr null, ptr %2, align 8 + %3 = load { ptr, ptr }, ptr %0, align 8 + ret { ptr, ptr } %3 +} + +declare i32 @printf(ptr, ...) + +define i64 @"main.main$1$1"(i64 %0, i64 %1) { +_llgo_0: + %2 = add i64 %0, %1 + ret i64 %2 +} + +define linkonce i64 @"__llgo_stub.main.main$1$1"(ptr %0, i64 %1, i64 %2) { +_llgo_0: + %3 = tail call i64 @"main.main$1$1"(i64 %1, i64 %2) + ret i64 %3 +} diff --git a/cl/compile.go b/cl/compile.go index 445d047f..bee1a4f4 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -573,6 +573,9 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue x := p.compileValue(b, v.X) t := p.prog.Type(v.AssertedType, llssa.InGo) ret = b.TypeAssert(x, t, v.CommaOk) + case *ssa.Extract: + x := p.compileValue(b, v.Tuple) + ret = b.Extract(x, v.Index) default: panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv)) } diff --git a/ssa/expr.go b/ssa/expr.go index 4fd644bd..80c69830 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -1137,6 +1137,21 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { return } +// The Extract instruction yields component Index of Tuple. +// +// This is used to access the results of instructions with multiple +// return values, such as Call, TypeAssert, Next, UnOp(ARROW) and +// IndexExpr(Map). +// +// Example printed form: +// +// t1 = extract t0 #1 +func (b Builder) Extract(x Expr, index int) (ret Expr) { + ret.Type = b.Prog.toType(x.Type.raw.Type.(*types.Tuple).At(index).Type()) + ret.impl = b.impl.CreateExtractValue(x.impl, index, "") + return +} + // A Builtin represents a specific use of a built-in function, e.g. len. // // Builtins are immutable values. Builtins do not have addresses. diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index a2e77687..bb1744b8 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -101,7 +101,9 @@ func (b Builder) Return(results ...Expr) { case 0: b.impl.CreateRetVoid() case 1: - b.impl.CreateRet(results[0].impl) + raw := b.Func.raw.Type.(*types.Signature).Results().At(0).Type() + ret := checkExpr(results[0], raw, b) + b.impl.CreateRet(ret.impl) default: tret := b.Func.raw.Type.(*types.Signature).Results() b.impl.CreateAggregateRet(llvmParams(0, results, tret, b))