From 94d567bf8f355f3ab096b8dd3383cc3efb84a1d0 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 10:24:10 +0800 Subject: [PATCH 01/18] testlibgo: math --- cl/_testlibgo/{_math => math}/in.go | 2 ++ cl/_testlibgo/math/out.ll | 52 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) rename cl/_testlibgo/{_math => math}/in.go (59%) create mode 100644 cl/_testlibgo/math/out.ll diff --git a/cl/_testlibgo/_math/in.go b/cl/_testlibgo/math/in.go similarity index 59% rename from cl/_testlibgo/_math/in.go rename to cl/_testlibgo/math/in.go index 8f31a5cb..8794dcc8 100644 --- a/cl/_testlibgo/_math/in.go +++ b/cl/_testlibgo/math/in.go @@ -5,5 +5,7 @@ import ( ) func main() { + println(math.Sqrt(2)) println(math.Abs(-1.2)) + println(math.Ldexp(1.2, 3)) } diff --git a/cl/_testlibgo/math/out.ll b/cl/_testlibgo/math/out.ll new file mode 100644 index 00000000..e7ee0e64 --- /dev/null +++ b/cl/_testlibgo/math/out.ll @@ -0,0 +1,52 @@ +; ModuleID = 'main' +source_filename = "main" + +@"main.init$guard" = global i1 false, align 1 +@__llgo_argc = global i32 0, align 4 +@__llgo_argv = global ptr null, align 8 + +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 + call void @math.init() + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define i32 @main(i32 %0, ptr %1) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %2 = call double @math.Sqrt(double 2.000000e+00) + call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %2) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %3 = call double @math.Abs(double -1.200000e+00) + call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %3) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %4 = call double @math.Ldexp(double 1.200000e+00, i64 3) + call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %4) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + ret i32 0 +} + +declare void @math.init() + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare double @math.Sqrt(double) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) + +declare double @math.Abs(double) + +declare double @math.Ldexp(double, i64) From 1599ba02946c2587856d1d1792a087831ff12ea3 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 10:41:28 +0800 Subject: [PATCH 02/18] private closureCtx/closureStub --- internal/lib/math/math.go | 4 ++++ ssa/decl.go | 7 ------- ssa/package.go | 9 +++++++-- ssa/type_cvt.go | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/lib/math/math.go b/internal/lib/math/math.go index 588cbae5..be6f1c8d 100644 --- a/internal/lib/math/math.go +++ b/internal/lib/math/math.go @@ -22,6 +22,10 @@ import ( "github.com/goplus/llgo/c" ) +const ( + LLGoPackage = true +) + //go:linkname Acos C.acos func Acos(x float64) float64 diff --git a/ssa/decl.go b/ssa/decl.go index caffa5fe..9e4a6ca6 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -26,13 +26,6 @@ import ( // ----------------------------------------------------------------------------- -const ( - ClosureCtx = "__llgo_ctx" - ClosureStub = "__llgo_stub." -) - -// ----------------------------------------------------------------------------- - const ( NameValist = "__llgo_va_list" ) diff --git a/ssa/package.go b/ssa/package.go index 9ef00f79..2a04994f 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -564,6 +564,11 @@ func (p Package) cFunc(fullName string, sig *types.Signature) Expr { return p.NewFunc(fullName, sig, InC).Expr } +const ( + closureCtx = "__llgo_ctx" + closureStub = "__llgo_stub." +) + func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr { name := v.impl.Name() prog := b.Prog @@ -574,9 +579,9 @@ func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr { sig := v.raw.Type.(*types.Signature) n := sig.Params().Len() nret := sig.Results().Len() - ctx := types.NewParam(token.NoPos, nil, ClosureCtx, types.Typ[types.UnsafePointer]) + ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer]) sig = FuncAddCtx(ctx, sig) - fn := p.NewFunc(ClosureStub+name, sig, InC) + fn := p.NewFunc(closureStub+name, sig, InC) fn.impl.SetLinkage(llvm.LinkOnceAnyLinkage) args := make([]Expr, n) for i := 0; i < n; i++ { diff --git a/ssa/type_cvt.go b/ssa/type_cvt.go index a9314a68..299a0970 100644 --- a/ssa/type_cvt.go +++ b/ssa/type_cvt.go @@ -133,7 +133,7 @@ func (p goTypes) cvtNamed(t *types.Named) (raw *types.Named, cvt bool) { } func (p goTypes) cvtClosure(sig *types.Signature) *types.Struct { - ctx := types.NewParam(token.NoPos, nil, ClosureCtx, types.Typ[types.UnsafePointer]) + ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer]) raw := p.cvtFunc(sig, ctx) flds := []*types.Var{ types.NewField(token.NoPos, nil, "f", raw, false), From fa712aa3a0c78a81d8bb0e195e7f5ce31e4908b8 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 11:44:52 +0800 Subject: [PATCH 03/18] build: aPackage.AltPkg/AltSSA --- internal/build/build.go | 45 ++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index 57170518..82e1bfd8 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -145,7 +145,14 @@ func Do(args []string, conf *Config) { return rt[1].Types }) - pkgs := buildAllPkgs(prog, initial, nil, mode, verbose) + imp := func(pkgPath string) *packages.Package { + if ret, e := packages.LoadEx(sizes, cfg, pkgPath); e == nil { + return ret[0] + } + return nil + } + + pkgs := buildAllPkgs(prog, imp, initial, nil, mode, verbose) var runtimeFiles []string if needRt { @@ -153,7 +160,7 @@ func Do(args []string, conf *Config) { for _, v := range pkgs { skip[v.PkgPath] = true } - dpkg := buildAllPkgs(prog, rt[:1], skip, mode, verbose) + dpkg := buildAllPkgs(prog, imp, rt[:1], skip, mode, verbose) for _, pkg := range dpkg { if !strings.HasSuffix(pkg.ExportFile, ".ll") { continue @@ -192,9 +199,9 @@ func isNeedRuntimeOrPyInit(pkg *packages.Package) (needRuntime, needPyInit bool) return } -func buildAllPkgs(prog llssa.Program, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) { +func buildAllPkgs(prog llssa.Program, imp importer, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) { // Create SSA-form program representation. - ssaProg, pkgs, errPkgs := allPkgs(initial, ssa.SanityCheckFunctions) + ssaProg, pkgs, errPkgs := allPkgs(imp, initial, ssa.SanityCheckFunctions) ssaProg.Build() for _, errPkg := range errPkgs { for _, err := range errPkg.Errors { @@ -379,11 +386,21 @@ func canSkipToBuild(pkgPath string) bool { type aPackage struct { *packages.Package - SSA *ssa.Package - LPkg llssa.Package + SSA *ssa.Package + AltPkg *packages.Package + AltSSA *ssa.Package + LPkg llssa.Package } -func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) { +type none struct{} + +var hasAltPkg = map[string]none{ + "math": {}, +} + +type importer = func(pkgPath string) *packages.Package + +func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) { var fset *token.FileSet if len(initial) > 0 { fset = initial[0].Fset @@ -392,8 +409,18 @@ func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Progr prog = ssa.NewProgram(fset, mode) packages.Visit(initial, nil, func(p *packages.Package) { if p.Types != nil && !p.IllTyped { - ssaPkg := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) - all = append(all, &aPackage{p, ssaPkg, nil}) + var altPkg *packages.Package + var altSSA *ssa.Package + var ssaPkg = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) + if imp != nil { + if _, ok := hasAltPkg[p.PkgPath]; ok { + altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath + if altPkg = imp(altPkgPath); altPkg != nil { + altSSA = prog.CreatePackage(altPkg.Types, altPkg.Syntax, altPkg.TypesInfo, true) + } + } + } + all = append(all, &aPackage{p, ssaPkg, altPkg, altSSA, nil}) } else { errs = append(errs, p) } From e0a25b509815c423133d8212430fbb825ae31cd2 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 12:10:08 +0800 Subject: [PATCH 04/18] NewPackage: altSSA --- cl/cltest/cltest.go | 2 +- cl/compile.go | 2 +- internal/build/build.go | 7 ++++++- internal/llgen/llgen.go | 2 +- internal/llgen/llgenf.go | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go index 6b1208c1..fbe500be 100644 --- a/cl/cltest/cltest.go +++ b/cl/cltest/cltest.go @@ -143,7 +143,7 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) { foo.WriteTo(os.Stderr) prog := ssatest.NewProgramEx(t, nil, imp) - ret, err := cl.NewPackage(prog, foo, files) + ret, err := cl.NewPackage(prog, foo, nil, files) if err != nil { t.Fatal("cl.NewPackage failed:", err) } diff --git a/cl/compile.go b/cl/compile.go index 4239f465..06ca17f5 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -953,7 +953,7 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) // ----------------------------------------------------------------------------- // NewPackage compiles a Go package to LLVM IR package. -func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { +func NewPackage(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { type namedMember struct { name string val ssa.Member diff --git a/internal/build/build.go b/internal/build/build.go index 82e1bfd8..eacb4277 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -365,7 +365,12 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) { pkg.ExportFile = "" return } - ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax) + syntax := pkg.Syntax + if altPkg := aPkg.AltPkg; altPkg != nil { + // TODO: merge pkg.Types + syntax = append(syntax, altPkg.Syntax...) + } + ret, err := cl.NewPackage(prog, aPkg.SSA, aPkg.AltSSA, syntax) check(err) if needLLFile(mode) { pkg.ExportFile += ".ll" diff --git a/internal/llgen/llgen.go b/internal/llgen/llgen.go index 2a62b637..d50dfe56 100644 --- a/internal/llgen/llgen.go +++ b/internal/llgen/llgen.go @@ -80,7 +80,7 @@ func Gen(pkgPath, inFile string, src any) string { return ret }) - ret, err := cl.NewPackage(prog, ssaPkg, files) + ret, err := cl.NewPackage(prog, ssaPkg, nil, files) check(err) if prog.NeedPyInit { // call PyInit if needed diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 843c245a..36adf090 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -80,7 +80,7 @@ func GenFrom(fileOrPkg string) string { ssaPkg.WriteTo(os.Stderr) } - ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax) + ret, err := cl.NewPackage(prog, ssaPkg, nil, pkg.Syntax) check(err) if prog.NeedPyInit { // call PyInit if needed From a45be62b6880a6682d0e8101a57919fdad0a64c7 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 12:43:05 +0800 Subject: [PATCH 05/18] cl.NewPackageEx --- cl/cltest/cltest.go | 2 +- cl/compile.go | 43 +++++++++++++++++++++++++++------------- internal/build/build.go | 4 ++-- internal/llgen/llgen.go | 2 +- internal/llgen/llgenf.go | 2 +- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go index fbe500be..6b1208c1 100644 --- a/cl/cltest/cltest.go +++ b/cl/cltest/cltest.go @@ -143,7 +143,7 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) { foo.WriteTo(os.Stderr) prog := ssatest.NewProgramEx(t, nil, imp) - ret, err := cl.NewPackage(prog, foo, nil, files) + ret, err := cl.NewPackage(prog, foo, files) if err != nil { t.Fatal("cl.NewPackage failed:", err) } diff --git a/cl/compile.go b/cl/compile.go index 06ca17f5..61b97d49 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -953,20 +953,14 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) // ----------------------------------------------------------------------------- // NewPackage compiles a Go package to LLVM IR package. -func NewPackage(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { - type namedMember struct { - name string - val ssa.Member - } - - members := make([]*namedMember, 0, len(pkg.Members)) - for name, v := range pkg.Members { - members = append(members, &namedMember{name, v}) - } - sort.Slice(members, func(i, j int) bool { - return members[i].name < members[j].name - }) +func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { + return NewPackageEx(prog, pkg, nil, files) +} +// NewPackageEx compiles a Go package (pkg) to LLVM IR package. +// The Go package may have an alternative package (alt). +// The pkg and alt have the same (Pkg *types.Package). +func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { pkgProg := pkg.Prog pkgTypes := pkg.Pkg pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes) @@ -990,6 +984,28 @@ func NewPackage(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (r } ctx.initPyModule() ctx.initFiles(pkgPath, files) + + if alt != nil { + processPkg(ctx, ret, alt) + } + processPkg(ctx, ret, pkg) + return +} + +func processPkg(ctx *context, ret llssa.Package, pkg *ssa.Package) { + type namedMember struct { + name string + val ssa.Member + } + + members := make([]*namedMember, 0, len(pkg.Members)) + for name, v := range pkg.Members { + members = append(members, &namedMember{name, v}) + } + sort.Slice(members, func(i, j int) bool { + return members[i].name < members[j].name + }) + for _, m := range members { member := m.val switch member := member.(type) { @@ -1013,7 +1029,6 @@ func NewPackage(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (r ini() } } - return } // ----------------------------------------------------------------------------- diff --git a/internal/build/build.go b/internal/build/build.go index eacb4277..670656f2 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -34,10 +34,10 @@ import ( "github.com/goplus/llgo/cl" "github.com/goplus/llgo/internal/packages" "github.com/goplus/llgo/xtool/clang" - clangCheck "github.com/goplus/llgo/xtool/clang/check" "github.com/goplus/llgo/xtool/env" llssa "github.com/goplus/llgo/ssa" + clangCheck "github.com/goplus/llgo/xtool/clang/check" ) type Mode int @@ -370,7 +370,7 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) { // TODO: merge pkg.Types syntax = append(syntax, altPkg.Syntax...) } - ret, err := cl.NewPackage(prog, aPkg.SSA, aPkg.AltSSA, syntax) + ret, err := cl.NewPackageEx(prog, aPkg.SSA, aPkg.AltSSA, syntax) check(err) if needLLFile(mode) { pkg.ExportFile += ".ll" diff --git a/internal/llgen/llgen.go b/internal/llgen/llgen.go index d50dfe56..2a62b637 100644 --- a/internal/llgen/llgen.go +++ b/internal/llgen/llgen.go @@ -80,7 +80,7 @@ func Gen(pkgPath, inFile string, src any) string { return ret }) - ret, err := cl.NewPackage(prog, ssaPkg, nil, files) + ret, err := cl.NewPackage(prog, ssaPkg, files) check(err) if prog.NeedPyInit { // call PyInit if needed diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 36adf090..843c245a 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -80,7 +80,7 @@ func GenFrom(fileOrPkg string) string { ssaPkg.WriteTo(os.Stderr) } - ret, err := cl.NewPackage(prog, ssaPkg, nil, pkg.Syntax) + ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax) check(err) if prog.NeedPyInit { // call PyInit if needed From 7d8bed16b0feb7b21e0499c6f61b6652b38de0b9 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 13:08:11 +0800 Subject: [PATCH 06/18] createAltSSAPkg --- internal/build/build.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index 670656f2..fdbc92bb 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -367,7 +367,6 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) { } syntax := pkg.Syntax if altPkg := aPkg.AltPkg; altPkg != nil { - // TODO: merge pkg.Types syntax = append(syntax, altPkg.Syntax...) } ret, err := cl.NewPackageEx(prog, aPkg.SSA, aPkg.AltSSA, syntax) @@ -421,7 +420,9 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p if _, ok := hasAltPkg[p.PkgPath]; ok { altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath if altPkg = imp(altPkgPath); altPkg != nil { - altSSA = prog.CreatePackage(altPkg.Types, altPkg.Syntax, altPkg.TypesInfo, true) + altSSA = createAltSSAPkg(prog, altPkg) + altSSA.Pkg = p.Types + // TODO(xsw): merge p.Types and altPkg.Types } } } @@ -433,6 +434,18 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p return } +func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package { + packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) { + typ := p.Types + if typ != nil && !p.IllTyped { + if prog.ImportedPackage(typ.Path()) == nil { + prog.CreatePackage(typ, p.Syntax, p.TypesInfo, true) + } + } + }) + return prog.ImportedPackage(alt.Types.Path()) +} + var ( // TODO(xsw): complete build flags buildFlags = map[string]bool{ From 994502077af10b07ff440c17ba0a7273cf85741b Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 14:56:03 +0800 Subject: [PATCH 07/18] cl: collectSkipNames; processPkg bugfix --- c/math/math.go | 3 --- cl/compile.go | 25 ++++++++++++++++--------- cl/import.go | 39 +++++++++++++++++++++++++++++++++++---- internal/lib/math/math.go | 8 +------- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/c/math/math.go b/c/math/math.go index ee6c4932..063acc00 100644 --- a/c/math/math.go +++ b/c/math/math.go @@ -149,9 +149,6 @@ func Nextafter(x, y float64) float64 //go:linkname Pow C.pow func Pow(x, y float64) float64 -//go:linkname Pow10 C.pow10 -func Pow10(x c.Int) float64 - //go:linkname Remainder C.remainder func Remainder(x, y float64) float64 diff --git a/cl/compile.go b/cl/compile.go index 61b97d49..c84e43d3 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -136,6 +136,8 @@ type pkgInfo struct { kind int } +type none struct{} + type context struct { prog llssa.Program pkg llssa.Package @@ -145,7 +147,8 @@ type context struct { goTyps *types.Package goPkg *ssa.Package pyMod string - link map[string]string // pkgPath.nameInPkg => linkname + link map[string]string // pkgPath.nameInPkg => linkname + skips map[string]none loaded map[*types.Package]*pkgInfo // loaded packages bvals map[ssa.Value]llssa.Expr // block values vargs map[*ssa.Alloc][]llssa.Expr // varargs @@ -977,6 +980,7 @@ func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) goTyps: pkgTypes, goPkg: pkg, link: make(map[string]string), + skips: make(map[string]none), vargs: make(map[*ssa.Alloc][]llssa.Expr), loaded: map[*types.Package]*pkgInfo{ types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly? @@ -989,6 +993,13 @@ func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) processPkg(ctx, ret, alt) } processPkg(ctx, ret, pkg) + for len(ctx.inits) > 0 { + inits := ctx.inits + ctx.inits = nil + for _, ini := range inits { + ini() + } + } return } @@ -999,8 +1010,11 @@ func processPkg(ctx *context, ret llssa.Package, pkg *ssa.Package) { } members := make([]*namedMember, 0, len(pkg.Members)) + skips := ctx.skips for name, v := range pkg.Members { - members = append(members, &namedMember{name, v}) + if _, ok := skips[name]; !ok { + members = append(members, &namedMember{name, v}) + } } sort.Slice(members, func(i, j int) bool { return members[i].name < members[j].name @@ -1022,13 +1036,6 @@ func processPkg(ctx *context, ret llssa.Package, pkg *ssa.Package) { ctx.compileGlobal(ret, member) } } - for len(ctx.inits) > 0 { - inits := ctx.inits - ctx.inits = nil - for _, ini := range inits { - ini() - } - } } // ----------------------------------------------------------------------------- diff --git a/cl/import.go b/cl/import.go index a79144d6..970758a2 100644 --- a/cl/import.go +++ b/cl/import.go @@ -168,10 +168,20 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) { fullName, inPkgName := astFuncName(pkgPath, decl) p.initLinknameByDoc(decl.Doc, fullName, inPkgName, false) case *ast.GenDecl: - if decl.Tok == token.VAR && len(decl.Specs) == 1 { - if names := decl.Specs[0].(*ast.ValueSpec).Names; len(names) == 1 { - inPkgName := names[0].Name - p.initLinknameByDoc(decl.Doc, pkgPath+"."+inPkgName, inPkgName, true) + switch decl.Tok { + case token.VAR: + if len(decl.Specs) == 1 { + if names := decl.Specs[0].(*ast.ValueSpec).Names; len(names) == 1 { + inPkgName := names[0].Name + p.initLinknameByDoc(decl.Doc, pkgPath+"."+inPkgName, inPkgName, true) + } + } + case token.IMPORT: + if doc := decl.Doc; doc != nil { + if n := len(doc.List); n > 0 { + line := doc.List[n-1].Text + p.collectSkipNames(line) + } } } } @@ -179,6 +189,27 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) { } } +func (p *context) collectSkipNames(line string) { + const ( + skip = "//llgo:skip " + skip2 = "// llgo:skip " + ) + if strings.HasPrefix(line, skip2) { + p.collectSkip(line, len(skip2)) + } else if strings.HasPrefix(line, skip) { + p.collectSkip(line, len(skip)) + } +} + +func (p *context) collectSkip(line string, prefix int) { + names := strings.Split(line[prefix:], " ") + for _, name := range names { + if name != "" { + p.skips[name] = none{} + } + } +} + func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar bool) { if doc != nil { if n := len(doc.List); n > 0 { diff --git a/internal/lib/math/math.go b/internal/lib/math/math.go index be6f1c8d..09ccdaac 100644 --- a/internal/lib/math/math.go +++ b/internal/lib/math/math.go @@ -16,6 +16,7 @@ package math +// llgo:skip sin cos import ( _ "unsafe" @@ -173,13 +174,6 @@ func Nextafter(x, y float64) float64 //go:linkname Pow C.pow func Pow(x, y float64) float64 -//go:linkname cPow10 C.pow10 -func cPow10(x c.Int) float64 - -func Pow10(x int) float64 { - return cPow10(c.Int(x)) -} - //go:linkname Remainder C.remainder func Remainder(x, y float64) float64 From 5011c394d791b4b69bbaffd68f9f7ad1893421d0 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 15:52:44 +0800 Subject: [PATCH 08/18] build: use typepatch.Pkg merge patches of a standard library --- cl/import.go | 18 ++++++---- internal/build/build.go | 10 ++++-- internal/typepatch/patch.go | 66 +++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 internal/typepatch/patch.go diff --git a/cl/import.go b/cl/import.go index 970758a2..171ea4d9 100644 --- a/cl/import.go +++ b/cl/import.go @@ -65,15 +65,19 @@ func (p *pkgSymInfo) addSym(fset *token.FileSet, pos token.Pos, fullName, inPkgN } func (p *pkgSymInfo) initLinknames(ctx *context) { + sep := []byte{'\n'} + commentPrefix := []byte{'/', '/'} for file, b := range p.files { - lines := bytes.Split(b, []byte{'\n'}) + lines := bytes.Split(b, sep) for _, line := range lines { - ctx.initLinkname(string(line), func(inPkgName string) (fullName string, isVar, ok bool) { - if sym, ok := p.syms[inPkgName]; ok && file == sym.file { - return sym.fullName, sym.isVar, true - } - return - }) + if bytes.HasPrefix(line, commentPrefix) { + ctx.initLinkname(string(line), func(inPkgName string) (fullName string, isVar, ok bool) { + if sym, ok := p.syms[inPkgName]; ok && file == sym.file { + return sym.fullName, sym.isVar, true + } + return + }) + } } } } diff --git a/internal/build/build.go b/internal/build/build.go index fdbc92bb..f1f260f0 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -33,6 +33,7 @@ import ( "github.com/goplus/llgo/cl" "github.com/goplus/llgo/internal/packages" + "github.com/goplus/llgo/internal/typepatch" "github.com/goplus/llgo/xtool/clang" "github.com/goplus/llgo/xtool/env" @@ -94,6 +95,7 @@ func Do(args []string, conf *Config) { cfg := &packages.Config{ Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile, BuildFlags: flags, + Fset: token.NewFileSet(), } llssa.Initialize(llssa.InitAll) @@ -365,11 +367,15 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) { pkg.ExportFile = "" return } + altSSA := aPkg.AltSSA syntax := pkg.Syntax if altPkg := aPkg.AltPkg; altPkg != nil { syntax = append(syntax, altPkg.Syntax...) + if altSSA != nil { + altSSA.Pkg = typepatch.Pkg(pkg.Types, altPkg.Types) + } } - ret, err := cl.NewPackageEx(prog, aPkg.SSA, aPkg.AltSSA, syntax) + ret, err := cl.NewPackageEx(prog, aPkg.SSA, altSSA, syntax) check(err) if needLLFile(mode) { pkg.ExportFile += ".ll" @@ -421,8 +427,6 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath if altPkg = imp(altPkgPath); altPkg != nil { altSSA = createAltSSAPkg(prog, altPkg) - altSSA.Pkg = p.Types - // TODO(xsw): merge p.Types and altPkg.Types } } } diff --git a/internal/typepatch/patch.go b/internal/typepatch/patch.go new file mode 100644 index 00000000..ae17a2a5 --- /dev/null +++ b/internal/typepatch/patch.go @@ -0,0 +1,66 @@ +/* + * 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 typepatch + +import ( + "go/token" + "go/types" + "unsafe" +) + +type typesScope struct { + parent *types.Scope + children []*types.Scope + number int + elems map[string]types.Object // TODO(xsw): ensure offset of elems + pos, end token.Pos + comment string + isFunc bool +} + +type object struct { + parent *types.Scope + pos token.Pos + pkg *types.Package // TODO(xsw): ensure offset of pkg + unused [8]byte +} + +type iface struct { + tab unsafe.Pointer + data unsafe.Pointer +} + +func setPkg(o types.Object, pkg *types.Package) { + data := (*iface)(unsafe.Pointer(&o)).data + (*object)(data).pkg = pkg +} + +func setObject(scope *types.Scope, name string, o types.Object) { + s := (*typesScope)(unsafe.Pointer(scope)) + s.elems[name] = o +} + +func Pkg(pkg, alt *types.Package) *types.Package { + scope := pkg.Scope() + altScope := alt.Scope() + for _, name := range altScope.Names() { + o := altScope.Lookup(name) + setPkg(o, pkg) + setObject(scope, name, o) + } + return pkg +} From b668175c625cd7ffa361f2700406a911fca92885 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 15:58:22 +0800 Subject: [PATCH 09/18] go package demo: math --- README.md | 1 + _demo/math/math.go | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 _demo/math/math.go diff --git a/README.md b/README.md index 190fe3a4..06e8b0b7 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,7 @@ Here are the Go packages that can be imported correctly: * [unicode/utf8](https://pkg.go.dev/unicode/utf8) * [unicode/utf16](https://pkg.go.dev/unicode/utf16) * [math/bits](https://pkg.go.dev/math/bits) +* [math](https://pkg.go.dev/math) ## How to install diff --git a/_demo/math/math.go b/_demo/math/math.go new file mode 100644 index 00000000..8794dcc8 --- /dev/null +++ b/_demo/math/math.go @@ -0,0 +1,11 @@ +package main + +import ( + "math" +) + +func main() { + println(math.Sqrt(2)) + println(math.Abs(-1.2)) + println(math.Ldexp(1.2, 3)) +} From 764e0f0e7f16063e24aa5c205b9a3779c37b55f4 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 16:08:10 +0800 Subject: [PATCH 10/18] TestGoLibMath --- c/sqlite/llgo_autogen.lla | Bin 854 -> 854 bytes cl/compile_test.go | 6 ++++++ 2 files changed, 6 insertions(+) diff --git a/c/sqlite/llgo_autogen.lla b/c/sqlite/llgo_autogen.lla index ffb75f469ff7e8036085769e52f3f9478baa0b86..736d703bad2e8f611dbb93786a35e65a52bca1a2 100644 GIT binary patch delta 49 zcmcb{c8!fUz?+#xgn@y9gW-9@`H8%$?3=uE)3$i$ZnWIT#0(Ug{ENw$87MZ{fLRRy Df+G;V delta 49 zcmcb{c8!fUz?+#xgn@y9gQ3y)+(ceg_M`>bX(5a>3>2Gez^n!U DWXlhe diff --git a/cl/compile_test.go b/cl/compile_test.go index dbd9c939..cc3e5112 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/goplus/llgo/cl/cltest" + "github.com/goplus/llgo/internal/build" "github.com/goplus/llgo/ssa" ) @@ -64,6 +65,11 @@ func TestPython(t *testing.T) { cltest.Pkg(t, ssa.PkgPython, "../py/llgo_autogen.ll") } +func TestGoLibMath(t *testing.T) { + conf := build.NewDefaultConf(build.ModeInstall) + build.Do([]string{"math"}, conf) +} + func TestVar(t *testing.T) { testCompile(t, `package foo From 4aa3d321fa0e2f291e063921e9d4915a4f51a3d5 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 16:26:37 +0800 Subject: [PATCH 11/18] cltest.InitDebug --- cl/cltest/cltest.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go index 6b1208c1..7c6cb59a 100644 --- a/cl/cltest/cltest.go +++ b/cl/cltest/cltest.go @@ -41,8 +41,11 @@ import ( ) func init() { - cl.SetDebug(cl.DbgFlagAll) llssa.Initialize(llssa.InitAll | llssa.InitNative) +} + +func InitDebug() { + cl.SetDebug(cl.DbgFlagAll) llssa.SetDebug(llssa.DbgFlagAll) } From 3a6f5dd4eec4418e62838f5061c9e8d8d7571503 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 17:40:05 +0800 Subject: [PATCH 12/18] createAltSSAPkg --- internal/build/build.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index f1f260f0..ac6d95de 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -201,9 +201,13 @@ func isNeedRuntimeOrPyInit(pkg *packages.Package) (needRuntime, needPyInit bool) return } +const ( + ssaBuildMode = ssa.SanityCheckFunctions +) + func buildAllPkgs(prog llssa.Program, imp importer, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) { // Create SSA-form program representation. - ssaProg, pkgs, errPkgs := allPkgs(imp, initial, ssa.SanityCheckFunctions) + ssaProg, pkgs, errPkgs := allPkgs(imp, initial, ssaBuildMode) ssaProg.Build() for _, errPkg := range errPkgs { for _, err := range errPkg.Errors { @@ -425,7 +429,7 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p if imp != nil { if _, ok := hasAltPkg[p.PkgPath]; ok { altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath - if altPkg = imp(altPkgPath); altPkg != nil { + if altPkg = imp(altPkgPath); altPkg != nil { // TODO(xsw): how to minimize import times altSSA = createAltSSAPkg(prog, altPkg) } } @@ -439,15 +443,20 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p } func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package { - packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) { - typ := p.Types - if typ != nil && !p.IllTyped { - if prog.ImportedPackage(typ.Path()) == nil { - prog.CreatePackage(typ, p.Syntax, p.TypesInfo, true) + altPath := alt.Types.Path() + altSSA := prog.ImportedPackage(altPath) + if altSSA == nil { + packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) { + pkgTypes := p.Types + if pkgTypes != nil && !p.IllTyped { + if prog.ImportedPackage(pkgTypes.Path()) == nil { + prog.CreatePackage(pkgTypes, p.Syntax, p.TypesInfo, true) + } } - } - }) - return prog.ImportedPackage(alt.Types.Path()) + }) + altSSA = prog.ImportedPackage(altPath) + } + return altSSA } var ( From 287722b1d299e267953cd131e3081cbed51ba740 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 17:56:45 +0800 Subject: [PATCH 13/18] setPkgSSA --- internal/build/build.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/build/build.go b/internal/build/build.go index ac6d95de..1a130122 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -28,6 +28,7 @@ import ( "path/filepath" "runtime" "strings" + "unsafe" "golang.org/x/tools/go/ssa" @@ -442,6 +443,17 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p return } +type ssaProgram struct { + Fset *token.FileSet + imported map[string]*ssa.Package + packages map[*types.Package]*ssa.Package // TODO(xsw): ensure offset of packages +} + +func setPkgSSA(prog *ssa.Program, pkg *types.Package, pkgSSA *ssa.Package) { + s := (*ssaProgram)(unsafe.Pointer(prog)) + s.packages[pkg] = pkgSSA +} + func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package { altPath := alt.Types.Path() altSSA := prog.ImportedPackage(altPath) @@ -449,8 +461,11 @@ func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package { packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) { pkgTypes := p.Types if pkgTypes != nil && !p.IllTyped { - if prog.ImportedPackage(pkgTypes.Path()) == nil { + pkgSSA := prog.ImportedPackage(pkgTypes.Path()) + if pkgSSA == nil { prog.CreatePackage(pkgTypes, p.Syntax, p.TypesInfo, true) + } else { + setPkgSSA(prog, pkgTypes, pkgSSA) } } }) From 71518b025d89e5a1fe582446b61e3dcb40531a97 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 18:02:51 +0800 Subject: [PATCH 14/18] TestGoLibMath: set LLGOROOT --- cl/compile_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cl/compile_test.go b/cl/compile_test.go index cc3e5112..553b171d 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -17,6 +17,8 @@ package cl_test import ( + "os" + "path/filepath" "testing" "github.com/goplus/llgo/cl/cltest" @@ -66,6 +68,8 @@ func TestPython(t *testing.T) { } func TestGoLibMath(t *testing.T) { + root, _ := filepath.Abs("..") + os.Setenv("LLGOROOT", root) conf := build.NewDefaultConf(build.ModeInstall) build.Do([]string{"math"}, conf) } From 7f11651311d9cd68221133becb07a0c5bc8d9a14 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 18:08:08 +0800 Subject: [PATCH 15/18] TestGoLibMath: mac only (temp) --- cl/compile_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cl/compile_test.go b/cl/compile_test.go index 553b171d..40980b1a 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -19,6 +19,7 @@ package cl_test import ( "os" "path/filepath" + "runtime" "testing" "github.com/goplus/llgo/cl/cltest" @@ -68,10 +69,12 @@ func TestPython(t *testing.T) { } func TestGoLibMath(t *testing.T) { - root, _ := filepath.Abs("..") - os.Setenv("LLGOROOT", root) - conf := build.NewDefaultConf(build.ModeInstall) - build.Do([]string{"math"}, conf) + if runtime.GOOS == "darwin" { // TODO(xsw): support linux/windows + root, _ := filepath.Abs("..") + os.Setenv("LLGOROOT", root) + conf := build.NewDefaultConf(build.ModeInstall) + build.Do([]string{"math"}, conf) + } } func TestVar(t *testing.T) { From dcb8eb7d6df8d788576ef64307cc29d0cb9ae573 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 18:22:26 +0800 Subject: [PATCH 16/18] TestCollectSkipNames --- .github/workflows/go.yml | 4 ---- cl/builtin_test.go | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 7f8ad77c..6887ed30 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -52,11 +52,7 @@ jobs: - name: Build run: go build -v ./... - - name: Test - if: matrix.os != 'ubuntu-latest' - run: go test -v ./... - name: Test with coverage - if: matrix.os == 'ubuntu-latest' run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./... - name: Install diff --git a/cl/builtin_test.go b/cl/builtin_test.go index 5f5a49dd..08b95e87 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -27,6 +27,11 @@ import ( "golang.org/x/tools/go/ssa" ) +func TestCollectSkipNames(t *testing.T) { + ctx := &context{skips: make(map[string]none)} + ctx.collectSkipNames("//llgo:skip abs") +} + func TestReplaceGoName(t *testing.T) { if ret := replaceGoName("foo", 0); ret != "foo" { t.Fatal("replaceGoName:", ret) @@ -155,6 +160,9 @@ func TestPkgKind(t *testing.T) { if v, _ := pkgKind("noinit"); v != PkgNoInit { t.Fatal("pkgKind:", v) } + if v, _ := pkgKind("link"); v != PkgLinkIR { + t.Fatal("pkgKind:", v) + } if v, _ := pkgKind(""); v != PkgLLGo { t.Fatal("pkgKind:", v) } From 00c73b8388a2720e571462537703dc7c394b4cc6 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 18:28:39 +0800 Subject: [PATCH 17/18] ci --- .github/workflows/go.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6887ed30..4e9e236d 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -52,7 +52,12 @@ jobs: - name: Build run: go build -v ./... + - name: Test + if: matrix.os != 'macos-latest' + run: go test -v ./... + - name: Test with coverage + if: matrix.os == 'macos-latest' run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./... - name: Install From 0a5a0ef31913e3966e81dba83580ce12041782b7 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 15 Jun 2024 18:41:45 +0800 Subject: [PATCH 18/18] cl/ssa.SetDebug --- cl/compile_test.go | 3 +++ ssa/cl_test.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/cl/compile_test.go b/cl/compile_test.go index 40980b1a..8c4f9706 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -22,6 +22,7 @@ import ( "runtime" "testing" + "github.com/goplus/llgo/cl" "github.com/goplus/llgo/cl/cltest" "github.com/goplus/llgo/internal/build" "github.com/goplus/llgo/ssa" @@ -49,7 +50,9 @@ func TestFromTestlibc(t *testing.T) { } func TestFromTestrt(t *testing.T) { + cl.SetDebug(cl.DbgFlagAll) cltest.FromDir(t, "", "./_testrt", true) + cl.SetDebug(0) } func TestFromTestdata(t *testing.T) { diff --git a/ssa/cl_test.go b/ssa/cl_test.go index be5cde02..cea2ce03 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -25,6 +25,10 @@ import ( "github.com/goplus/llgo/ssa/ssatest" ) +func init() { + ssa.SetDebug(ssa.DbgFlagAll) +} + func TestFromTestgo(t *testing.T) { cltest.FromDir(t, "", "../cl/_testgo", false) }