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 93% rename from cl/_testrt/intgen/out.ll rename to cl/_testrt/_intgen/out.ll index 54f38550..144fd31b 100644 --- a/cl/_testrt/intgen/out.ll +++ b/cl/_testrt/_intgen/out.ll @@ -21,10 +21,11 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0 br i1 %8, label %_llgo_2, label %_llgo_3 _llgo_2: ; preds = %_llgo_1 - %9 = extractvalue { ptr, ptr } %1, 0 - %10 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %4) - %11 = getelementptr inbounds i32, ptr %10, i64 %7 - store i32 0, ptr %11, align 4 + %9 = extractvalue { i32 ()*, ptr } %1, 0 + %10 = call i32 ()* %9() + %11 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %4) + %12 = getelementptr inbounds i32, ptr %11, i64 %7 + store ptr %10, ptr %12, align 8 br label %_llgo_1 _llgo_3: ; preds = %_llgo_1 diff --git a/cl/compile.go b/cl/compile.go index 907e1d5c..d4e58a07 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -184,10 +184,7 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { if debugInstr { log.Println("==> NewVar", name, typ) } - if vtype == cVar { - typ = llssa.CType(typ) - } - g := pkg.NewVar(name, typ) + g := pkg.NewVar(name, typ, llssa.Background(vtype)) if vtype == goVar { g.Init(p.prog.Null(g.Type)) } @@ -196,13 +193,13 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function, closure bool) llssa.Function { var sig = f.Signature var name string + var ftype int if closure { - name = funcName(pkgTypes, f) + name, ftype = funcName(pkgTypes, f), goFunc if debugInstr { log.Println("==> NewClosure", name, "type:", sig) } } else { - var ftype int name, ftype = p.funcName(pkgTypes, f, true) switch ftype { case ignoredFunc, llgoInstr: // llgo extended instructions @@ -211,11 +208,8 @@ func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa if debugInstr { log.Println("==> NewFunc", name, "type:", sig.Recv(), sig) } - if ftype == cFunc { - sig = llssa.CFuncDecl(sig) - } } - fn := pkg.NewFunc(name, sig) + fn := pkg.NewFunc(name, sig, llssa.Background(ftype)) p.inits = append(p.inits, func() { p.fn = fn defer func() { @@ -265,7 +259,8 @@ const ( ) func callRuntimeInit(b llssa.Builder, pkg llssa.Package) { - fn := pkg.NewFunc(RuntimeInit, types.NewSignatureType(nil, nil, nil, nil, nil, false)) + sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) + fn := pkg.NewFunc(RuntimeInit, sig, llssa.InC) // don't need to convert runtime.init b.Call(fn.Expr) } @@ -372,7 +367,7 @@ func (p *context) compilePhis(b llssa.Builder, instrs []ssa.Instruction) []ssa.I } func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) { - phi := b.Phi(p.prog.Type(v.Type())) + phi := b.Phi(p.prog.Type(v.Type(), llssa.InGo)) ret = phi.Expr p.phis = append(p.phis, func() { preds := v.Block().Preds @@ -451,11 +446,11 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue case *ssa.ChangeType: t := v.Type() x := p.compileValue(b, v.X) - ret = b.ChangeType(p.prog.Type(t), x) + ret = b.ChangeType(p.prog.Type(t, llssa.InGo), x) case *ssa.Convert: t := v.Type() x := p.compileValue(b, v.X) - ret = b.Convert(p.prog.Type(t), x) + ret = b.Convert(p.prog.Type(t, llssa.InGo), x) case *ssa.FieldAddr: x := p.compileValue(b, v.X) ret = b.FieldAddr(x, v.Field) @@ -464,7 +459,8 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue if p.checkVArgs(v, t) { // varargs: this is a varargs allocation return } - ret = b.Alloc(t, v.Heap) + elem := p.prog.Type(t.Elem(), llssa.InGo) + ret = b.Alloc(elem, v.Heap) case *ssa.IndexAddr: vx := v.X if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index @@ -505,24 +501,24 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue const ( delayExpr = true // varargs: don't need to convert an expr to any ) - t := v.Type() + t := p.prog.Type(v.Type(), llssa.InGo) x := p.compileValue(b, v.X) ret = b.MakeInterface(t, x, delayExpr) case *ssa.MakeSlice: var nCap llssa.Expr - t := v.Type() + t := p.prog.Type(v.Type(), llssa.InGo) nLen := p.compileValue(b, v.Len) if v.Cap != nil { nCap = p.compileValue(b, v.Cap) } - ret = b.MakeSlice(p.prog.Type(t), nLen, nCap) + ret = b.MakeSlice(t, nLen, nCap) case *ssa.MakeMap: var nReserve llssa.Expr - t := v.Type() + t := p.prog.Type(v.Type(), llssa.InGo) if v.Reserve != nil { nReserve = p.compileValue(b, v.Reserve) } - ret = b.MakeMap(p.prog.Type(t), nReserve) + ret = b.MakeMap(t, nReserve) /* case *ssa.MakeClosure: fn := p.compileValue(b, v.Fn) @@ -531,7 +527,8 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue */ case *ssa.TypeAssert: x := p.compileValue(b, v.X) - ret = b.TypeAssert(x, p.prog.Type(v.AssertedType), v.CommaOk) + t := p.prog.Type(v.AssertedType, llssa.InGo) + ret = b.TypeAssert(x, t, v.CommaOk) default: panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv)) } @@ -622,7 +619,7 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr { return g.Expr case *ssa.Const: t := types.Default(v.Type()) - return b.Const(v.Value, p.prog.Type(t)) + return b.Const(v.Value, p.prog.Type(t, llssa.InGo)) } panic(fmt.Sprintf("compileValue: unknown value - %T\n", v)) } diff --git a/cl/import.go b/cl/import.go index 463988eb..53f70cd2 100644 --- a/cl/import.go +++ b/cl/import.go @@ -191,9 +191,9 @@ func checkCgo(fnName string) bool { const ( ignoredFunc = iota - goFunc - cFunc - llgoInstr = -1 + goFunc = int(llssa.InGo) + cFunc = int(llssa.InC) + llgoInstr = -1 llgoInstrBase = 0x80 llgoUnreachable = llgoInstrBase + 0 @@ -222,8 +222,8 @@ func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (s const ( ignoredVar = iota - goVar - cVar + goVar = int(llssa.InGo) + cVar = int(llssa.InC) ) func (p *context) varName(pkg *types.Package, v *ssa.Global) (vName string, vtype int) { @@ -256,7 +256,8 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) { panic("unknown llgo instruction: " + name) } } else if ret = pkg.FuncOf(name); ret == nil { - ret = pkg.NewFunc(name, fn.Signature) + sig := fn.Signature + ret = pkg.NewFunc(name, sig, llssa.Background(ftype)) } return } @@ -264,9 +265,9 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) { func (p *context) varOf(v *ssa.Global) (ret llssa.Global) { pkgTypes := p.ensureLoaded(v.Pkg.Pkg) pkg := p.pkg - name, _ := p.varName(pkgTypes, v) + name, vtype := p.varName(pkgTypes, v) if ret = pkg.VarOf(name); ret == nil { - ret = pkg.NewVar(name, v.Type()) + ret = pkg.NewVar(name, v.Type(), llssa.Background(vtype)) } return } diff --git a/ssa/cl_test.go b/ssa/cl_test.go index 6fa9eeb0..a2046fc2 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -17,12 +17,9 @@ 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) { @@ -38,6 +35,7 @@ func TestRuntime(t *testing.T) { 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) @@ -51,3 +49,4 @@ func TestMap(t *testing.T) { t.Fatal("At(csig):", v) } } +*/ diff --git a/ssa/decl.go b/ssa/decl.go index 942a1623..aae14e79 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -25,6 +25,24 @@ import ( // ----------------------------------------------------------------------------- +const ( + NameValist = "__llgo_va_list" +) + +func VArg() *types.Var { + return types.NewParam(0, nil, NameValist, types.Typ[types.Invalid]) +} + +func IsVArg(arg *types.Var) bool { + return arg.Name() == NameValist +} + +func HasVArg(t *types.Tuple, n int) bool { + return n > 0 && IsVArg(t.At(n-1)) +} + +// ----------------------------------------------------------------------------- + type aNamedConst struct { } @@ -123,7 +141,7 @@ func newFunction(fn llvm.Value, t Type, pkg Package, prog Program) Function { } func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { - sig := fn.t.(*types.Signature) + sig := fn.raw.Type.(*types.Signature) in := sig.Params() if n := in.Len(); n > 0 { if hasVArg = HasVArg(in, n); hasVArg { @@ -131,7 +149,7 @@ func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { } params = make([]Type, n) for i := 0; i < n; i++ { - params[i] = prog.Type(in.At(i).Type()) + params[i] = prog.rawType(in.At(i).Type()) } } return diff --git a/ssa/expr.go b/ssa/expr.go index 2948d5fd..73e7802a 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -41,20 +41,13 @@ func (v Expr) IsNil() bool { return v.Type == nil } -/* -// TypeOf returns the type of the expression. -func (v Expr) TypeOf() types.Type { - return v.t -} -*/ - // Do evaluates the delay expression and returns the result. func (v Expr) Do(b Builder) Expr { switch vt := v.Type; vt.kind { case vkDelayExpr: - return vt.t.(delayExprTy)() + return vt.raw.Type.(delayExprTy)() case vkPhisExpr: - e := vt.t.(*phisExprTy) + e := vt.raw.Type.(*phisExprTy) return b.aggregateValue(e.Type, e.phis...) } return v @@ -64,7 +57,7 @@ func (v Expr) Do(b Builder) Expr { // DelayExpr returns a delay expression. func DelayExpr(f func() Expr) Expr { - return Expr{Type: &aType{t: delayExprTy(f), kind: vkDelayExpr}} + return Expr{Type: &aType{raw: rawType{delayExprTy(f)}, kind: vkDelayExpr}} } type delayExprTy func() Expr @@ -93,7 +86,7 @@ func (p phisExprTy) String() string { } func phisExpr(t Type, phis []llvm.Value) Expr { - return Expr{Type: &aType{t: &phisExprTy{phis, t}, kind: vkPhisExpr}} + return Expr{Type: &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr}} } // ----------------------------------------------------------------------------- @@ -148,7 +141,8 @@ func (b Builder) Const(v constant.Value, typ Type) Expr { if v == nil { return prog.Null(typ) } - switch t := typ.t.(type) { + raw := typ.raw.Type + switch t := raw.(type) { case *types.Basic: kind := t.Kind() switch { @@ -170,7 +164,7 @@ func (b Builder) Const(v constant.Value, typ Type) Expr { return b.Str(constant.StringVal(v)) } } - panic(fmt.Sprintf("unsupported Const: %v, %v", v, typ.t)) + panic(fmt.Sprintf("unsupported Const: %v, %v", v, raw)) } // SizeOf returns the size of a type. @@ -362,11 +356,11 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr { // ----------------------------------------------------------------------------- func checkExpr(v Expr, t types.Type, b Builder) Expr { - if _, ok := t.(*types.Signature); ok { + if _, ok := t.(*types.Struct); ok { if v.kind != vkClosure { prog := b.Prog nilVal := prog.Null(prog.VoidPtr()).impl - return b.aggregateValue(prog.Type(t), v.impl, nilVal) + return b.aggregateValue(prog.rawType(t), v.impl, nilVal) } } return v @@ -413,7 +407,7 @@ func (p Phi) AddIncoming(b Builder, bblks []BasicBlock, f func(i int) Expr) { p.impl.AddIncoming(vs, bs) return } - e := p.t.(*phisExprTy) + e := p.raw.Type.(*phisExprTy) phis := e.phis vals := make([][]llvm.Value, len(phis)) for iblk, blk := range bblks { @@ -436,7 +430,7 @@ func (p Phi) AddIncoming(b Builder, bblks []BasicBlock, f func(i int) Expr) { // Phi returns a phi node. func (b Builder) Phi(t Type) Phi { impl := b.impl - switch tund := t.t.Underlying().(type) { + switch tund := t.raw.Type.Underlying().(type) { case *types.Basic: kind := tund.Kind() switch kind { @@ -447,6 +441,8 @@ func (b Builder) Phi(t Type) Phi { phis[1] = llvm.CreatePHI(impl, prog.tyInt()) return Phi{phisExpr(t, phis)} } + case *types.Struct: + panic("todo") } phi := llvm.CreatePHI(impl, t.ll) return Phi{Expr{phi, t}} @@ -484,7 +480,7 @@ func (b Builder) Store(ptr, val Expr) Builder { // aggregateValue yields the value of the aggregate X with the fields func (b Builder) aggregateValue(t Type, flds ...llvm.Value) Expr { if debugInstr { - log.Printf("AggregateValue %v, %v\n", t.t, flds) + log.Printf("AggregateValue %v, %v\n", t.RawType(), flds) } impl := b.impl tll := t.ll @@ -542,8 +538,9 @@ 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} + tfld := b.Prog.Field(x.Type, idx) + fld := llvm.CreateExtractValue(b.impl, x.impl, idx) + return Expr{fld, tfld} } // The IndexAddr instruction yields the address of the element at @@ -565,7 +562,7 @@ func (b Builder) IndexAddr(x, idx Expr) Expr { prog := b.Prog telem := prog.Index(x.Type) pt := prog.Pointer(telem) - switch x.t.Underlying().(type) { + switch x.raw.Type.Underlying().(type) { case *types.Slice: pkg := b.fn.pkg ptr := b.InlineCall(pkg.rtFunc("SliceData"), x) @@ -591,12 +588,12 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr { prog := b.Prog var telem Type var ptr Expr - switch t := x.t.Underlying().(type) { + switch t := x.raw.Type.Underlying().(type) { case *types.Basic: if t.Info()&types.IsString == 0 { panic(fmt.Errorf("invalid operation: cannot index %v", t)) } - telem = prog.Type(types.Typ[types.Byte]) + telem = prog.rawType(types.Typ[types.Byte]) pkg := b.fn.pkg ptr = b.InlineCall(pkg.rtFunc("StringData"), x) case *types.Array: @@ -639,7 +636,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) { if low.IsNil() { low = prog.IntVal(0, prog.Int()) } - switch t := x.t.Underlying().(type) { + switch t := x.raw.Type.Underlying().(type) { case *types.Basic: if t.Kind() != types.String { panic(fmt.Errorf("invalid operation: cannot slice %v", t)) @@ -662,7 +659,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) { telem := t.Elem() switch te := telem.Underlying().(type) { case *types.Array: - elem := prog.Type(te.Elem()) + elem := prog.rawType(te.Elem()) ret.Type = prog.Slice(elem) nEltSize = b.SizeOf(elem) nCap = prog.IntVal(uint64(te.Len()), prog.Int()) @@ -692,7 +689,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) { // t1 = make StringIntMap t0 func (b Builder) MakeMap(t Type, nReserve Expr) (ret Expr) { if debugInstr { - log.Printf("MakeMap %v, %v\n", t, nReserve.impl) + log.Printf("MakeMap %v, %v\n", t.RawType(), nReserve.impl) } pkg := b.fn.pkg ret.Type = t @@ -717,7 +714,7 @@ func (b Builder) MakeMap(t Type, nReserve Expr) (ret Expr) { // t1 = make StringSlice 1:int t0 func (b Builder) MakeSlice(t Type, len, cap Expr) (ret Expr) { if debugInstr { - log.Printf("MakeSlice %v, %v, %v\n", t, len.impl, cap.impl) + log.Printf("MakeSlice %v, %v, %v\n", t.RawType(), len.impl, cap.impl) } pkg := b.fn.pkg if cap.IsNil() { @@ -752,13 +749,12 @@ func (b Builder) MakeSlice(t Type, len, cap Expr) (ret Expr) { // // t0 = local int // t1 = new int -func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) { +func (b Builder) Alloc(elem Type, heap bool) (ret Expr) { if debugInstr { - log.Printf("Alloc %v, %v\n", t, heap) + log.Printf("Alloc %v, %v\n", elem.RawType(), heap) } prog := b.Prog pkg := b.fn.pkg - elem := prog.Type(t.Elem()) size := b.SizeOf(elem) if heap { ret = b.InlineCall(pkg.rtFunc("AllocZ"), size) @@ -766,7 +762,7 @@ func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) { ret = Expr{llvm.CreateAlloca(b.impl, elem.ll), prog.VoidPtr()} ret.impl = b.InlineCall(pkg.rtFunc("Zeroinit"), ret, size).impl } - ret.Type = prog.Type(t) + ret.Type = prog.Pointer(elem) return } @@ -778,7 +774,7 @@ func (b Builder) Alloca(n Expr) (ret Expr) { prog := b.Prog telem := prog.tyInt8() ret.impl = llvm.CreateArrayAlloca(b.impl, telem, n.impl) - ret.Type = &aType{prog.tyVoidPtr(), types.Typ[types.UnsafePointer], vkPtr} + ret.Type = prog.VoidPtr() return } @@ -833,13 +829,14 @@ func (b Builder) AllocaCStr(gostr Expr) (ret Expr) { // t1 = changetype *int <- IntPtr (t0) func (b Builder) ChangeType(t Type, x Expr) (ret Expr) { if debugInstr { - log.Printf("ChangeType %v, %v\n", t.t, x.impl) + log.Printf("ChangeType %v, %v\n", t.RawType(), x.impl) } - typ := t.t + typ := t.raw.Type switch typ.(type) { default: + // TODO(xsw): remove instr name ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast") - ret.Type = b.Prog.Type(typ) + ret.Type = b.Prog.rawType(typ) return } } @@ -871,8 +868,8 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) { // // t1 = convert []byte <- string (t0) func (b Builder) Convert(t Type, x Expr) (ret Expr) { - typ := t.t - ret.Type = b.Prog.Type(typ) + typ := t.raw.Type + ret.Type = b.Prog.rawType(typ) switch und := typ.Underlying().(type) { case *types.Basic: kind := und.Kind() @@ -923,17 +920,17 @@ func castPtr(b llvm.Builder, x llvm.Value, t llvm.Type) llvm.Value { // // t1 = make interface{} <- int (42:int) // t2 = make Stringer <- t0 -func (b Builder) MakeInterface(inter types.Type, x Expr, mayDelay bool) (ret Expr) { +func (b Builder) MakeInterface(tinter Type, x Expr, mayDelay bool) (ret Expr) { + raw := tinter.raw.Type if debugInstr { - log.Printf("MakeInterface %v, %v\n", inter, x.impl) + log.Printf("MakeInterface %v, %v\n", raw, x.impl) } - tiund := inter.Underlying().(*types.Interface) + tiund := raw.Underlying().(*types.Interface) isAny := tiund.Empty() fnDo := func() Expr { prog := b.Prog pkg := b.fn.pkg - tinter := prog.Type(inter) - switch tx := x.t.Underlying().(type) { + switch tx := x.raw.Type.Underlying().(type) { case *types.Basic: kind := tx.Kind() switch { @@ -995,7 +992,7 @@ func (b Builder) MakeInterface(inter types.Type, x Expr, mayDelay bool) (ret Exp // t3 = typeassert,ok t2.(T) func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) { if debugInstr { - log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.t, commaOk) + log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.raw.Type, commaOk) } switch assertedTyp.kind { case vkSigned, vkUnsigned, vkFloat: @@ -1006,7 +1003,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) { } fn := pkg.rtFunc(fnName) var kind types.BasicKind - switch t := assertedTyp.t.(type) { + switch t := assertedTyp.raw.Type.(type) { case *types.Basic: kind = t.Kind() default: @@ -1044,7 +1041,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { if name == "" { name = "closure" } - fmt.Fprint(&b, "Call ", fn.t, " ", name) + fmt.Fprint(&b, "Call ", fn.raw.Type, " ", name) sep := ": " for _, arg := range args { fmt.Fprint(&b, sep, arg.impl) @@ -1053,25 +1050,19 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { log.Println(b.String()) } var sig *types.Signature - var t = fn.t - normal := true + var raw = fn.raw.Type switch fn.kind { case vkClosure: - fn = b.Field(fn, 0) - t = fn.t - normal = false + fn := b.Field(fn, 0) + raw = fn.raw.Type fallthrough - case vkFuncDecl, vkFuncPtr: - sig = t.(*types.Signature) + case vkFunc: + sig = raw.(*types.Signature) ret.Type = prog.retType(sig) default: panic("unreachable") } - if normal { - ret.impl = llvm.CreateCall(b.impl, fn.ll, fn.impl, llvmValues(args, sig.Params(), b)) - } else { - ret = prog.IntVal(0, prog.Type(types.Typ[types.Int32])) - } + ret.impl = llvm.CreateCall(b.impl, fn.ll, fn.impl, llvmValues(args, sig.Params(), b)) return } @@ -1086,7 +1077,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { case "len": if len(args) == 1 { arg := args[0] - switch t := arg.t.Underlying().(type) { + switch t := arg.raw.Type.Underlying().(type) { case *types.Slice: return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg) case *types.Basic: @@ -1098,7 +1089,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { case "cap": if len(args) == 1 { arg := args[0] - switch arg.t.Underlying().(type) { + switch arg.raw.Type.Underlying().(type) { case *types.Slice: return b.InlineCall(b.fn.pkg.rtFunc("SliceCap"), arg) } diff --git a/ssa/package.go b/ssa/package.go index 406c52c5..f75e0e84 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -18,6 +18,7 @@ package ssa import ( "go/types" + "log" "github.com/goplus/llgo/internal/typeutil" "github.com/goplus/llvm" @@ -94,9 +95,9 @@ func Initialize(flags InitFlags) { // ----------------------------------------------------------------------------- type aProgram struct { - ctx llvm.Context - typs typeutil.Map - // sizs types.Sizes + ctx llvm.Context + typs typeutil.Map // rawType -> Type + gocvt goTypes rt *types.Package rtget func() *types.Package @@ -152,7 +153,7 @@ func NewProgram(target *Target) Program { // TODO(xsw): Finalize may cause panic, so comment it. ctx.Finalize() */ - return &aProgram{ctx: ctx, target: target, td: td} + return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td} } // SetRuntime sets the runtime. @@ -180,11 +181,13 @@ func (p Program) runtime() *types.Package { } func (p Program) rtNamed(name string) *types.Named { - return p.runtime().Scope().Lookup(name).Type().(*types.Named) + t := p.runtime().Scope().Lookup(name).Type().(*types.Named) + t, _ = p.gocvt.cvtNamed(t) + return t } func (p Program) rtType(name string) Type { - return p.Type(p.rtNamed(name)) + return p.rawType(p.rtNamed(name)) } func (p Program) rtIface() llvm.Type { @@ -229,14 +232,14 @@ func (p Program) NewPackage(name, pkgPath string) Package { // Void returns void type. func (p Program) Void() Type { if p.voidTy == nil { - p.voidTy = &aType{p.tyVoid(), types.Typ[types.Invalid], vkInvalid} + p.voidTy = &aType{p.tyVoid(), rawType{types.Typ[types.Invalid]}, vkInvalid} } return p.voidTy } func (p Program) VoidPtr() Type { if p.voidPtr == nil { - p.voidPtr = p.Type(types.Typ[types.UnsafePointer]) + p.voidPtr = p.rawType(types.Typ[types.UnsafePointer]) } return p.voidPtr } @@ -244,21 +247,21 @@ func (p Program) VoidPtr() Type { // Bool returns bool type. func (p Program) Bool() Type { if p.boolTy == nil { - p.boolTy = p.Type(types.Typ[types.Bool]) + p.boolTy = p.rawType(types.Typ[types.Bool]) } return p.boolTy } func (p Program) CStr() Type { if p.cstrTy == nil { // *int8 - p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8])) + p.cstrTy = p.rawType(types.NewPointer(types.Typ[types.Int8])) } return p.cstrTy } func (p Program) String() Type { if p.stringTy == nil { - p.stringTy = p.Type(types.Typ[types.String]) + p.stringTy = p.rawType(types.Typ[types.String]) } return p.stringTy } @@ -266,7 +269,7 @@ func (p Program) String() Type { // Any returns any type. func (p Program) Any() Type { if p.anyTy == nil { - p.anyTy = p.Type(tyAny) + p.anyTy = p.rawType(tyAny) } return p.anyTy } @@ -274,7 +277,7 @@ func (p Program) Any() Type { // Int returns int type. func (p Program) Int() Type { if p.intTy == nil { - p.intTy = p.Type(types.Typ[types.Int]) + p.intTy = p.rawType(types.Typ[types.Int]) } return p.intTy } @@ -282,7 +285,7 @@ func (p Program) Int() Type { // Uintptr returns uintptr type. func (p Program) Uintptr() Type { if p.uintptrTy == nil { - p.uintptrTy = p.Type(types.Typ[types.Uintptr]) + p.uintptrTy = p.rawType(types.Typ[types.Uintptr]) } return p.uintptrTy } @@ -290,7 +293,7 @@ func (p Program) Uintptr() Type { // Float64 returns float64 type. func (p Program) Float64() Type { if p.f64Ty == nil { - p.f64Ty = p.Type(types.Typ[types.Float64]) + p.f64Ty = p.rawType(types.Typ[types.Float64]) } return p.f64Ty } @@ -322,8 +325,8 @@ func (p Package) NewConst(name string, val constant.Value) NamedConst { */ // NewVar creates a new global variable. -func (p Package) NewVar(name string, typ types.Type) Global { - t := p.prog.Type(typ) +func (p Package) NewVar(name string, typ types.Type, bg Background) Global { + t := p.prog.Type(typ, bg) gbl := llvm.AddGlobal(p.mod, t.ll, name) ret := &aGlobal{Expr{gbl, t}} p.vars[name] = ret @@ -336,26 +339,30 @@ func (p Package) VarOf(name string) Global { } // NewFunc creates a new function. -func (p Package) NewFunc(name string, sig *types.Signature) Function { +func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function { if v, ok := p.fns[name]; ok { return v } - t := p.prog.llvmFuncDecl(sig) + t := p.prog.FuncDecl(sig, bg) + if debugInstr { + log.Println("NewFunc", name, t.raw.Type) + } fn := llvm.AddFunction(p.mod, name, t.ll) ret := newFunction(fn, t, p, p.prog) p.fns[name] = ret return ret } -// FuncOf returns a function by name. -func (p Package) FuncOf(name string) Function { - return p.fns[name] -} - func (p Package) rtFunc(fnName string) Expr { fn := p.prog.runtime().Scope().Lookup(fnName).(*types.Func) name := FullName(fn.Pkg(), fnName) - return p.NewFunc(name, fn.Type().(*types.Signature)).Expr + sig := fn.Type().(*types.Signature) + return p.NewFunc(name, sig, InGo).Expr +} + +// FuncOf returns a function by name. +func (p Package) FuncOf(name string) Function { + return p.fns[name] } // ----------------------------------------------------------------------------- diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 838dd92a..361081a9 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -52,6 +52,7 @@ func TestIndexType(t *testing.T) { indexType(types.Typ[types.Int]) } +/* func TestCvtCType(t *testing.T) { test := func(typ types.Type) { defer func() { @@ -59,7 +60,7 @@ func TestCvtCType(t *testing.T) { t.Log("cvtCType: no error?") } }() - cvtCType(typ) + cvtGoType(typ) } test(types.NewInterfaceType(nil, nil)) @@ -77,6 +78,7 @@ func TestCFuncPtr(t *testing.T) { t.Fatal("TestCFuncPtr failed") } } +*/ func TestUserdefExpr(t *testing.T) { a := delayExprTy(nil) @@ -118,9 +120,9 @@ func assertPkg(t *testing.T, p Package, expected string) { func TestVar(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") - a := pkg.NewVar("a", types.Typ[types.Int]) + a := pkg.NewVar("a", types.Typ[types.Int], InGo) a.Init(prog.Val(100)) - b := pkg.NewVar("b", types.Typ[types.Int]) + b := pkg.NewVar("b", types.Typ[types.Int], InGo) b.Init(a.Expr) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @@ -135,7 +137,7 @@ func TestConst(t *testing.T) { pkg := prog.NewPackage("bar", "foo/bar") rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Bool])) sig := types.NewSignatureType(nil, nil, nil, nil, rets, false) - b := pkg.NewFunc("fn", sig).MakeBody(1) + b := pkg.NewFunc("fn", sig, InGo).MakeBody(1) b.Return(b.Const(constant.MakeBool(true), prog.Bool())) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @@ -152,7 +154,7 @@ func TestStruct(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") - pkg.NewVar("a", empty) + pkg.NewVar("a", empty, InGo) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @@ -169,7 +171,7 @@ func TestNamedStruct(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") - pkg.NewVar("a", empty) + pkg.NewVar("a", empty, InGo) if pkg.VarOf("a") == nil { t.Fatal("VarOf failed") } @@ -187,7 +189,7 @@ func TestDeclFunc(t *testing.T) { pkg := prog.NewPackage("bar", "foo/bar") params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, nil, false) - pkg.NewFunc("fn", sig) + pkg.NewFunc("fn", sig, InGo) if pkg.FuncOf("fn") == nil { t.Fatal("FuncOf failed") } @@ -209,7 +211,7 @@ func TestBasicFunc(t *testing.T) { types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - pkg.NewFunc("fn", sig).MakeBody(1). + pkg.NewFunc("fn", sig, InGo).MakeBody(1). Return(prog.Val(1)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @@ -229,7 +231,7 @@ func TestFuncParam(t *testing.T) { types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - fn := pkg.NewFunc("fn", sig) + fn := pkg.NewFunc("fn", sig, InGo) fn.MakeBody(1).Return(fn.Param(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @@ -250,12 +252,12 @@ func TestFuncCall(t *testing.T) { types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - fn := pkg.NewFunc("fn", sig) + fn := pkg.NewFunc("fn", sig, InGo) fn.MakeBody(1). Return(prog.Val(1)) sigMain := types.NewSignatureType(nil, nil, nil, nil, nil, false) - b := pkg.NewFunc("main", sigMain).MakeBody(1) + b := pkg.NewFunc("main", sigMain, InGo).MakeBody(1) b.Call(fn.Expr, prog.Val(1), prog.Val(1.2)) b.Return() @@ -284,8 +286,8 @@ func TestFuncMultiRet(t *testing.T) { types.NewVar(0, nil, "c", types.Typ[types.Int]), types.NewVar(0, nil, "d", types.Typ[types.Float64])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - a := pkg.NewVar("a", types.Typ[types.Int]) - fn := pkg.NewFunc("fn", sig) + a := pkg.NewVar("a", types.Typ[types.Int], InGo) + fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) b.Return(a.Expr, fn.Param(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' @@ -305,7 +307,7 @@ func TestJump(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) - fn := pkg.NewFunc("loop", sig) + fn := pkg.NewFunc("loop", sig, InGo) b := fn.MakeBody(1) b.Jump(fn.Block(0)) assertPkg(t, pkg, `; ModuleID = 'foo/bar' @@ -324,7 +326,7 @@ func TestIf(t *testing.T) { params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - fn := pkg.NewFunc("fn", sig) + fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(3) iftrue := fn.Block(1) iffalse := fn.Block(2) @@ -359,7 +361,7 @@ func TestPrintf(t *testing.T) { params := types.NewTuple(types.NewVar(0, nil, "format", pchar), VArg()) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int32])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - pkg.NewFunc("printf", sig) + pkg.NewFunc("printf", sig, InGo) assertPkg(t, pkg, `; ModuleID = 'foo/bar' source_filename = "foo/bar" @@ -375,7 +377,7 @@ func TestBinOp(t *testing.T) { types.NewVar(0, nil, "b", types.Typ[types.Float64])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - fn := pkg.NewFunc("fn", sig) + fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) ret := b.BinOp(token.ADD, fn.Param(0), prog.Val(1)) b.Return(ret) @@ -398,7 +400,7 @@ func TestUnOp(t *testing.T) { ) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])) sig := types.NewSignatureType(nil, nil, nil, params, rets, false) - fn := pkg.NewFunc("fn", sig) + fn := pkg.NewFunc("fn", sig, InGo) b := fn.MakeBody(1) ptr := fn.Param(0) val := b.UnOp(token.MUL, ptr) diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 73760543..f6978845 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -103,7 +103,7 @@ func (b Builder) Return(results ...Expr) { case 1: b.impl.CreateRet(results[0].impl) default: - tret := b.fn.t.(*types.Signature).Results() + tret := b.fn.raw.Type.(*types.Signature).Results() b.impl.CreateAggregateRet(llvmValues(results, tret, b)) } } diff --git a/ssa/type.go b/ssa/type.go index 0f31b058..48470aeb 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -18,7 +18,6 @@ package ssa import ( "fmt" - "go/token" "go/types" "github.com/goplus/llvm" @@ -41,9 +40,8 @@ const ( vkString vkBool vkPtr - vkFuncDecl // func decl - vkFuncPtr // func ptr in C - vkClosure // func ptr in Go + vkFunc + vkClosure vkTuple vkDelayExpr = -1 vkPhisExpr = -2 @@ -66,32 +64,25 @@ func indexType(t types.Type) types.Type { panic("index: type doesn't support index - " + t.String()) } -// convert method to func -func methodToFunc(sig *types.Signature) *types.Signature { - if recv := sig.Recv(); recv != nil { - tParams := sig.Params() - nParams := tParams.Len() - params := make([]*types.Var, nParams+1) - params[0] = recv - for i := 0; i < nParams; i++ { - params[i+1] = tParams.At(i) - } - return types.NewSignatureType( - nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) - } - return sig -} - // ----------------------------------------------------------------------------- +type rawType struct { + types.Type +} + type aType struct { ll llvm.Type - t types.Type + raw rawType kind valueKind // value kind of llvm.Type } type Type = *aType +// RawType returns the raw type. +func (t Type) RawType() types.Type { + return t.raw.Type +} + // TODO(xsw): // how to generate platform independent code? func (p Program) SizeOf(typ Type, n ...int64) uint64 { @@ -103,42 +94,37 @@ func (p Program) SizeOf(typ Type, n ...int64) uint64 { } func (p Program) Slice(typ Type) Type { - return p.Type(types.NewSlice(typ.t)) + return p.rawType(types.NewSlice(typ.raw.Type)) } func (p Program) Pointer(typ Type) Type { - return p.Type(types.NewPointer(typ.t)) + return p.rawType(types.NewPointer(typ.raw.Type)) } func (p Program) Elem(typ Type) Type { - elem := typ.t.(*types.Pointer).Elem() - return p.Type(elem) + elem := typ.raw.Type.(*types.Pointer).Elem() + return p.rawType(elem) } func (p Program) Index(typ Type) Type { - return p.Type(indexType(typ.t)) + return p.rawType(indexType(typ.raw.Type)) } func (p Program) Field(typ Type, i int) Type { - tunder := typ.t.Underlying() + tunder := typ.raw.Type.Underlying() tfld := tunder.(*types.Struct).Field(i).Type() - return p.Type(tfld) + return p.rawType(tfld) } -func (p Program) Type(typ types.Type) Type { - if v := p.typs.At(typ); v != nil { +func (p Program) rawType(raw types.Type) Type { + if v := p.typs.At(raw); v != nil { return v.(Type) } - ret := p.toLLVMType(typ) - p.typs.Set(typ, ret) + ret := p.toType(raw) + p.typs.Set(raw, ret) return ret } -func (p Program) llvmFuncDecl(sig *types.Signature) Type { - sig = methodToFunc(sig) - return p.toLLVMFunc(sig, false, true) // don't save func decl to cache -} - func (p Program) tyVoidPtr() llvm.Type { if p.voidPtrTy.IsNil() { p.voidPtrTy = llvm.PointerType(p.tyVoid(), 0) @@ -202,8 +188,9 @@ func (p Program) tyInt64() llvm.Type { return p.int64Type } -func (p Program) toLLVMType(typ types.Type) Type { - switch t := typ.(type) { +func (p Program) toType(raw types.Type) Type { + typ := rawType{raw} + switch t := raw.(type) { case *types.Basic: switch t.Kind() { case types.Int: @@ -240,7 +227,7 @@ func (p Program) toLLVMType(typ types.Type) Type { return &aType{p.tyVoidPtr(), typ, vkPtr} } case *types.Pointer: - elem := p.Type(t.Elem()) + elem := p.rawType(t.Elem()) return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr} case *types.Interface: return &aType{p.rtIface(), typ, vkInvalid} @@ -249,39 +236,37 @@ func (p Program) toLLVMType(typ types.Type) Type { case *types.Map: return &aType{p.rtMap(), typ, vkInvalid} case *types.Struct: - return p.toLLVMStruct(t) + return &aType{p.toLLVMStruct(t), typ, vkInvalid} case *types.Named: - return p.toLLVMNamed(t) - case *types.Signature: - return p.toLLVMFunc(t, false, false) - case *CFuncPtr: - return p.toLLVMFunc((*types.Signature)(t), true, false) + return p.toNamed(t) + case *types.Signature: // represents a C function pointer in raw type + return &aType{p.toLLVMFuncPtr(t), typ, vkFunc} case *types.Array: - elem := p.Type(t.Elem()) + elem := p.rawType(t.Elem()) return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} case *types.Chan: } panic(fmt.Sprintf("toLLVMType: todo - %T\n", typ)) } -func (p Program) toLLVMNamedStruct(name string, typ *types.Struct) llvm.Type { +func (p Program) toLLVMNamedStruct(name string, raw *types.Struct) llvm.Type { t := p.ctx.StructCreateNamed(name) - fields := p.toLLVMFields(typ) + fields := p.toLLVMFields(raw) t.StructSetBody(fields, false) return t } -func (p Program) toLLVMStruct(typ *types.Struct) Type { - fields := p.toLLVMFields(typ) - return &aType{p.ctx.StructType(fields, false), typ, vkInvalid} +func (p Program) toLLVMStruct(raw *types.Struct) llvm.Type { + fields := p.toLLVMFields(raw) + return p.ctx.StructType(fields, false) } -func (p Program) toLLVMFields(typ *types.Struct) (fields []llvm.Type) { - n := typ.NumFields() +func (p Program) toLLVMFields(raw *types.Struct) (fields []llvm.Type) { + n := raw.NumFields() if n > 0 { fields = make([]llvm.Type, n) for i := 0; i < n; i++ { - fields[i] = p.Type(typ.Field(i).Type()).ll + fields[i] = p.rawType(raw.Field(i).Type()).ll } } return @@ -295,69 +280,57 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) { if n > 0 { ret = make([]llvm.Type, n) for i := 0; i < n; i++ { - ret[i] = p.Type(t.At(i).Type()).ll + ret[i] = p.rawType(t.At(i).Type()).ll } } return } -func (p Program) toLLVMFunc(sig *types.Signature, inC, isDecl bool) Type { - if isDecl || inC { - tParams := sig.Params() - n := tParams.Len() - hasVArg := HasVArg(tParams, n) - if hasVArg { - n-- - } - 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() - case 1: - ret = p.Type(out.At(0).Type()).ll - default: - ret = p.toLLVMTuple(out) - } - ft := llvm.FunctionType(ret, params, hasVArg) - if isDecl { - kind = vkFuncDecl - } else { - ft = llvm.PointerType(ft, 0) - kind = vkFuncPtr - } - return &aType{ft, sig, kind} +func (p Program) toLLVMFunc(sig *types.Signature) llvm.Type { + tParams := sig.Params() + n := tParams.Len() + hasVArg := HasVArg(tParams, n) + if hasVArg { + n-- } - flds := []*types.Var{ - types.NewField(token.NoPos, nil, "f", (*CFuncPtr)(sig), false), - types.NewField(token.NoPos, nil, "data", types.Typ[types.UnsafePointer], false), + params := p.toLLVMTypes(tParams, n) + out := sig.Results() + var ret llvm.Type + switch nret := out.Len(); nret { + case 0: + ret = p.tyVoid() + case 1: + ret = p.rawType(out.At(0).Type()).ll + default: + ret = p.toLLVMTuple(out) } - t := types.NewStruct(flds, nil) - ll := p.ctx.StructType(p.toLLVMFields(t), false) - return &aType{ll, t, vkClosure} + return llvm.FunctionType(ret, params, hasVArg) } -func (p Program) retType(sig *types.Signature) Type { - out := sig.Results() +func (p Program) toLLVMFuncPtr(sig *types.Signature) llvm.Type { + ft := p.toLLVMFunc(sig) + return llvm.PointerType(ft, 0) +} + +func (p Program) retType(raw *types.Signature) Type { + out := raw.Results() switch n := out.Len(); n { case 0: return p.Void() case 1: - return p.Type(out.At(0).Type()) + return p.rawType(out.At(0).Type()) default: - return &aType{p.toLLVMTuple(out), out, vkTuple} + return &aType{p.toLLVMTuple(out), rawType{out}, vkTuple} } } -func (p Program) toLLVMNamed(typ *types.Named) Type { - switch t := typ.Underlying().(type) { +func (p Program) toNamed(raw *types.Named) Type { + switch t := raw.Underlying().(type) { case *types.Struct: - name := NameOf(typ) - return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid} + name := NameOf(raw) + return &aType{p.toLLVMNamedStruct(name, t), rawType{raw}, vkInvalid} default: - return p.Type(t) + return p.rawType(t) } } diff --git a/ssa/type_c.go b/ssa/type_c.go deleted file mode 100644 index 045644fe..00000000 --- a/ssa/type_c.go +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ssa - -import ( - "go/types" - - "github.com/goplus/llgo/internal/typeutil" -) - -// ----------------------------------------------------------------------------- - -const ( - NameValist = "__llgo_va_list" -) - -func VArg() *types.Var { - return types.NewParam(0, nil, NameValist, types.Typ[types.Invalid]) -} - -func IsVArg(arg *types.Var) bool { - return arg.Name() == NameValist -} - -func HasVArg(t *types.Tuple, n int) bool { - return n > 0 && IsVArg(t.At(n-1)) -} - -// ----------------------------------------------------------------------------- - -// CFuncPtr represents a C function pointer. -type CFuncPtr types.Signature - -func (t *CFuncPtr) String() string { return (*types.Signature)(t).String() } -func (t *CFuncPtr) Underlying() types.Type { return (*types.Signature)(t) } - -func (t *CFuncPtr) Hash(h typeutil.Hasher) uint32 { - return typeutil.HashSig(h, (*types.Signature)(t))*13 + 97 -} - -// ----------------------------------------------------------------------------- - -// CType convert a C type into Go. -func CType(typ types.Type) types.Type { - t, _ := cvtCType(typ) - return t -} - -// CFuncDecl convert a C function decl into Go signature. -func CFuncDecl(sig *types.Signature) *types.Signature { - hasVArg := sig.Variadic() - params, cvt1 := cvtTuple(sig.Params(), hasVArg) - results, cvt2 := cvtTuple(sig.Results(), false) - if cvt1 || cvt2 { - return types.NewSignatureType(nil, nil, nil, params, results, hasVArg) - } - return sig -} - -func cvtCType(typ types.Type) (types.Type, bool) { - switch t := typ.(type) { - case *types.Basic: - case *types.Pointer: - if elem, cvt := cvtCType(t.Elem()); cvt { - return types.NewPointer(elem), true - } - case *types.Struct: - return cvtCStruct(t) - case *types.Named: - if _, cvt := cvtCType(t.Underlying()); cvt { - panic("don't define named type") - } - case *types.Signature: - t = CFuncDecl(t) - return (*CFuncPtr)(t), true - case *types.Array: - if elem, cvt := cvtCType(t.Elem()); cvt { - return types.NewArray(elem, t.Len()), true - } - default: - panic("unreachable") - } - return typ, false -} - -func cvtTuple(t *types.Tuple, hasVArg bool) (*types.Tuple, bool) { - n := t.Len() - vars := make([]*types.Var, n) - needcvt := false - if hasVArg { - n-- - vars[n] = t.At(n) - } - for i := 0; i < n; i++ { - v := t.At(i) - if t, cvt := cvtCType(v.Type()); cvt { - v = types.NewParam(v.Pos(), v.Pkg(), v.Name(), t) - needcvt = true - } - vars[i] = v - } - if needcvt { - return types.NewTuple(vars...), true - } - return t, false -} - -func cvtCStruct(typ *types.Struct) (*types.Struct, bool) { - n := typ.NumFields() - flds := make([]*types.Var, n) - needcvt := false - for i := 0; i < n; i++ { - f := typ.Field(i) - if t, cvt := cvtCType(f.Type()); cvt { - f = types.NewField(f.Pos(), f.Pkg(), f.Name(), t, f.Anonymous()) - needcvt = true - } - flds[i] = f - } - if needcvt { - return types.NewStruct(flds, nil), true - } - return typ, false -} - -// ----------------------------------------------------------------------------- diff --git a/ssa/type_cvt.go b/ssa/type_cvt.go new file mode 100644 index 00000000..e32abf3d --- /dev/null +++ b/ssa/type_cvt.go @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ssa + +import ( + "go/token" + "go/types" + "unsafe" +) + +// ----------------------------------------------------------------------------- + +type goTypes struct { + typs map[unsafe.Pointer]unsafe.Pointer +} + +func newGoTypes() goTypes { + typs := make(map[unsafe.Pointer]unsafe.Pointer) + return goTypes{typs} +} + +type Background int + +const ( + inUnknown Background = iota + InGo + InC +) + +// Type convert a Go/C type into raw type. +// C type = raw type +// Go type: convert to raw type (because of closure) +func (p Program) Type(typ types.Type, bg Background) Type { + if bg == InGo { + typ, _ = p.gocvt.cvtType(typ) + } + return p.rawType(typ) +} + +// FuncDecl converts a Go/C function declaration into raw type. +func (p Program) FuncDecl(sig *types.Signature, bg Background) Type { + if bg == InGo { + sig = p.gocvt.cvtFunc(sig, true) + } + return &aType{p.toLLVMFunc(sig), rawType{sig}, vkFunc} +} + +func (p goTypes) cvtType(typ types.Type) (raw types.Type, cvt bool) { + switch t := typ.(type) { + case *types.Basic: + case *types.Pointer: + if elem, cvt := p.cvtType(t.Elem()); cvt { + return types.NewPointer(elem), true + } + case *types.Interface: + return p.cvtInterface(t) + case *types.Slice: + if elem, cvt := p.cvtType(t.Elem()); cvt { + return types.NewSlice(elem), true + } + case *types.Map: + key, cvt1 := p.cvtType(t.Key()) + elem, cvt2 := p.cvtType(t.Elem()) + if cvt1 || cvt2 { + return types.NewMap(key, elem), true + } + case *types.Struct: + return p.cvtStruct(t) + case *types.Named: + return p.cvtNamed(t) + case *types.Signature: + return p.cvtClosure(t), true + case *types.Array: + if elem, cvt := p.cvtType(t.Elem()); cvt { + return types.NewArray(elem, t.Len()), true + } + case *types.Chan: + if elem, cvt := p.cvtType(t.Elem()); cvt { + return types.NewChan(t.Dir(), elem), true + } + default: + panic("unreachable") + } + return typ, false +} + +func (p goTypes) cvtNamed(t *types.Named) (raw *types.Named, cvt bool) { + if v, ok := p.typs[unsafe.Pointer(t)]; ok { + raw = (*types.Named)(v) + cvt = t != raw + return + } + defer func() { + p.typs[unsafe.Pointer(t)] = unsafe.Pointer(raw) + }() + if tund, cvt := p.cvtType(t.Underlying()); cvt { + old := t.Obj() + obj := types.NewTypeName(old.Pos(), old.Pkg(), old.Name(), nil) + return types.NewNamed(obj, tund, nil), true + } + return t, false +} + +func (p goTypes) cvtClosure(sig *types.Signature) *types.Struct { + raw := p.cvtFunc(sig, false) + flds := []*types.Var{ + types.NewField(token.NoPos, nil, "f", raw, false), + types.NewField(token.NoPos, nil, "data", types.Typ[types.UnsafePointer], false), + } + return types.NewStruct(flds, nil) +} + +func (p goTypes) cvtFunc(sig *types.Signature, hasRecv bool) (raw *types.Signature) { + if v, ok := p.typs[unsafe.Pointer(sig)]; ok { + return (*types.Signature)(v) + } + defer func() { + p.typs[unsafe.Pointer(sig)] = unsafe.Pointer(raw) + }() + if hasRecv { + sig = methodToFunc(sig) + } + params, cvt1 := p.cvtTuple(sig.Params()) + results, cvt2 := p.cvtTuple(sig.Results()) + if cvt1 || cvt2 { + return types.NewSignatureType(nil, nil, nil, params, results, sig.Variadic()) + } + return sig +} + +func (p goTypes) cvtTuple(t *types.Tuple) (*types.Tuple, bool) { + n := t.Len() + vars := make([]*types.Var, n) + needcvt := false + for i := 0; i < n; i++ { + v := t.At(i) + if t, cvt := p.cvtType(v.Type()); cvt { + v = types.NewParam(v.Pos(), v.Pkg(), v.Name(), t) + needcvt = true + } + vars[i] = v + } + if needcvt { + return types.NewTuple(vars...), true + } + return t, false +} + +func (p goTypes) cvtExplicitMethods(typ *types.Interface) ([]*types.Func, bool) { + n := typ.NumExplicitMethods() + methods := make([]*types.Func, n) + needcvt := false + for i := 0; i < n; i++ { + m := typ.ExplicitMethod(i) + sig := m.Type().(*types.Signature) + if raw := p.cvtFunc(sig, false); sig != raw { + m = types.NewFunc(m.Pos(), m.Pkg(), m.Name(), raw) + needcvt = true + } + methods[i] = m + } + return methods, needcvt +} + +func (p goTypes) cvtEmbeddedTypes(typ *types.Interface) ([]types.Type, bool) { + n := typ.NumEmbeddeds() + embeddeds := make([]types.Type, n) + needcvt := false + for i := 0; i < n; i++ { + t := typ.EmbeddedType(i) + if raw, cvt := p.cvtType(t); cvt { + t = raw + needcvt = true + } + embeddeds[i] = t + } + return embeddeds, needcvt +} + +func (p goTypes) cvtInterface(typ *types.Interface) (raw *types.Interface, cvt bool) { + if v, ok := p.typs[unsafe.Pointer(typ)]; ok { + raw = (*types.Interface)(v) + cvt = typ != raw + return + } + defer func() { + p.typs[unsafe.Pointer(typ)] = unsafe.Pointer(raw) + }() + methods, cvt1 := p.cvtExplicitMethods(typ) + embeddeds, cvt2 := p.cvtEmbeddedTypes(typ) + if cvt1 || cvt2 { + return types.NewInterfaceType(methods, embeddeds), true + } + return typ, false +} + +func (p goTypes) cvtStruct(typ *types.Struct) (raw *types.Struct, cvt bool) { + if v, ok := p.typs[unsafe.Pointer(typ)]; ok { + raw = (*types.Struct)(v) + cvt = typ != raw + return + } + defer func() { + p.typs[unsafe.Pointer(typ)] = unsafe.Pointer(raw) + }() + n := typ.NumFields() + flds := make([]*types.Var, n) + needcvt := false + for i := 0; i < n; i++ { + f := typ.Field(i) + if t, cvt := p.cvtType(f.Type()); cvt { + f = types.NewField(f.Pos(), f.Pkg(), f.Name(), t, f.Anonymous()) + needcvt = true + } + flds[i] = f + } + if needcvt { + return types.NewStruct(flds, nil), true + } + return typ, false +} + +// ----------------------------------------------------------------------------- + +// convert method to func +func methodToFunc(sig *types.Signature) *types.Signature { + if recv := sig.Recv(); recv != nil { + tParams := sig.Params() + nParams := tParams.Len() + params := make([]*types.Var, nParams+1) + params[0] = recv + for i := 0; i < nParams; i++ { + params[i+1] = tParams.At(i) + } + return types.NewSignatureType( + nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) + } + return sig +} + +// -----------------------------------------------------------------------------