diff --git a/cl/_testrt/intgen/in.go b/cl/_testrt/_intgen/in.go similarity index 100% rename from cl/_testrt/intgen/in.go rename to cl/_testrt/_intgen/in.go diff --git a/cl/_testrt/intgen/out.ll b/cl/_testrt/_intgen/out.ll similarity index 100% rename from cl/_testrt/intgen/out.ll rename to cl/_testrt/_intgen/out.ll diff --git a/ssa/cl_test.go b/ssa/cl_test.go index b5630353..6fa9eeb0 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -17,9 +17,12 @@ package ssa_test import ( + "go/types" "testing" "github.com/goplus/llgo/cl/cltest" + "github.com/goplus/llgo/internal/typeutil" + "github.com/goplus/llgo/ssa" ) func TestFromTestrt(t *testing.T) { @@ -34,3 +37,17 @@ func TestRuntime(t *testing.T) { cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll") cltest.Pkg(t, "github.com/goplus/llgo/internal/abi", "../internal/abi/llgo_autogen.ll") } + +func TestMap(t *testing.T) { + var m typeutil.Map + sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) + m.Set(sig, 1) + csig := (*ssa.CFuncPtr)(sig) + m.Set(csig, 2) + if v := m.At(sig); v.(int) != 1 { + t.Fatal("At(sig):", v) + } + if v := m.At(csig); v.(int) != 2 { + t.Fatal("At(csig):", v) + } +} diff --git a/ssa/expr.go b/ssa/expr.go index d252122a..30217c72 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -504,6 +504,15 @@ func (b Builder) FieldAddr(x Expr, idx int) Expr { return Expr{llvm.CreateStructGEP(b.impl, tstruc.ll, x.impl, idx), pt} } +// The Field instruction yields the value of Field of struct X. +func (b Builder) Field(x Expr, idx int) Expr { + if debugInstr { + log.Printf("Field %v, %d\n", x.impl, idx) + } + telem := b.Prog.Field(x.Type, idx) + return Expr{llvm.CreateExtractValue(b.impl, x.impl, idx), telem} +} + // The IndexAddr instruction yields the address of the element at // index `idx` of collection `x`. `idx` is an integer expression. // @@ -995,21 +1004,30 @@ func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) { // t4 = t3() // t7 = invoke t5.Println(...t6) func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { + prog := b.Prog if debugInstr { var b bytes.Buffer - fmt.Fprint(&b, "Call ", fn.impl.Name()) + name := fn.impl.Name() + if name == "" { + name = "closure" + } + fmt.Fprint(&b, "Call ", fn.t, " ", name) + sep := ": " for _, arg := range args { - fmt.Fprint(&b, ", ", arg.impl) + fmt.Fprint(&b, sep, arg.impl) + sep = ", " } log.Println(b.String()) } t := fn.t switch fn.kind { case vkClosure: - panic("todo") + fn = b.Field(fn, 0) + t = fn.t + fallthrough case vkFuncDecl, vkFuncPtr: sig := t.(*types.Signature) - ret.Type = b.Prog.retType(sig) + ret.Type = prog.retType(sig) default: panic("todo") } diff --git a/ssa/type.go b/ssa/type.go index 5f83bbf0..00ef495d 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -18,6 +18,7 @@ package ssa import ( "fmt" + "go/token" "go/types" "github.com/goplus/llvm" @@ -94,7 +95,7 @@ type Type = *aType // TODO(xsw): // how to generate platform independent code? func (p Program) SizeOf(typ Type, n ...int64) uint64 { - size := p.td.TypeStoreSize(typ.ll) + size := p.td.TypeAllocSize(typ.ll) if len(n) != 0 { size *= uint64(n[0]) } @@ -120,7 +121,8 @@ func (p Program) Index(typ Type) Type { func (p Program) Field(typ Type, i int) Type { tunder := typ.t.Underlying() - return p.Type(tunder.(*types.Struct).Field(i).Type()) + tfld := tunder.(*types.Struct).Field(i).Type() + return p.Type(tfld) } func (p Program) Type(typ types.Type) Type { @@ -305,8 +307,6 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) { } func (p Program) toLLVMFunc(sig *types.Signature, inC, isDecl bool) Type { - var kind valueKind - var ft llvm.Type if isDecl || inC { tParams := sig.Params() n := tParams.Len() @@ -317,6 +317,7 @@ func (p Program) toLLVMFunc(sig *types.Signature, inC, isDecl bool) Type { params := p.toLLVMTypes(tParams, n) out := sig.Results() var ret llvm.Type + var kind valueKind switch nret := out.Len(); nret { case 0: ret = p.tyVoid() @@ -325,18 +326,20 @@ func (p Program) toLLVMFunc(sig *types.Signature, inC, isDecl bool) Type { default: ret = p.toLLVMTuple(out) } - ft = llvm.FunctionType(ret, params, hasVArg) + ft := llvm.FunctionType(ret, params, hasVArg) if isDecl { kind = vkFuncDecl } else { ft = llvm.PointerType(ft, 0) kind = vkFuncPtr } - } else { - ft = p.rtClosure() - kind = vkClosure + return &aType{ft, sig, kind} } - return &aType{ft, sig, kind} + flds := []*types.Var{ + types.NewField(token.NoPos, nil, "f", (*CFuncPtr)(sig), false), + types.NewField(token.NoPos, nil, "data", types.Typ[types.UnsafePointer], false), + } + return &aType{p.rtClosure(), types.NewStruct(flds, nil), vkClosure} } func (p Program) retType(sig *types.Signature) Type {