From 8c9b0285e485b2eb6e9e3e87390813facaa86a8e Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 16 Jun 2024 17:12:08 +0800 Subject: [PATCH 1/6] testrt: gotypes --- cl/_testrt/{_gotypes => gotypes}/in.go | 0 cl/_testrt/{_gotypes => gotypes}/out.ll | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename cl/_testrt/{_gotypes => gotypes}/in.go (100%) rename cl/_testrt/{_gotypes => gotypes}/out.ll (88%) diff --git a/cl/_testrt/_gotypes/in.go b/cl/_testrt/gotypes/in.go similarity index 100% rename from cl/_testrt/_gotypes/in.go rename to cl/_testrt/gotypes/in.go diff --git a/cl/_testrt/_gotypes/out.ll b/cl/_testrt/gotypes/out.ll similarity index 88% rename from cl/_testrt/_gotypes/out.ll rename to cl/_testrt/gotypes/out.ll index ae8de993..571235f3 100644 --- a/cl/_testrt/_gotypes/out.ll +++ b/cl/_testrt/gotypes/out.ll @@ -3,9 +3,9 @@ source_filename = "main" %"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr } -@"main.init$guard" = global ptr null -@__llgo_argc = global ptr null -@__llgo_argv = global ptr null +@"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.foo(%"github.com/goplus/llgo/internal/runtime.iface" %0) { _llgo_0: From 7b7b4e5f22eb01e15f3b7acefaf7e2c55ec339cd Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 16 Jun 2024 20:49:31 +0800 Subject: [PATCH 2/6] patch sync/atomic --- cl/_testlibgo/{_atomic => atomic}/in.go | 0 internal/build/build.go | 3 ++- internal/lib/sync/atomic/atomic.go | 33 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) rename cl/_testlibgo/{_atomic => atomic}/in.go (100%) create mode 100644 internal/lib/sync/atomic/atomic.go diff --git a/cl/_testlibgo/_atomic/in.go b/cl/_testlibgo/atomic/in.go similarity index 100% rename from cl/_testlibgo/_atomic/in.go rename to cl/_testlibgo/atomic/in.go diff --git a/internal/build/build.go b/internal/build/build.go index c8744e42..552a71f1 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -413,7 +413,8 @@ type aPackage struct { type none struct{} var hasAltPkg = map[string]none{ - "math": {}, + "math": {}, + "sync/atomic": {}, } type importer = func(pkgPath string) *packages.Package diff --git a/internal/lib/sync/atomic/atomic.go b/internal/lib/sync/atomic/atomic.go new file mode 100644 index 00000000..f62c5356 --- /dev/null +++ b/internal/lib/sync/atomic/atomic.go @@ -0,0 +1,33 @@ +/* + * 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 atomic + +// llgo:skip init +import ( + _ "unsafe" +) + +const ( + LLGoPackage = true +) + +//go:linkname cAddInt64 llgo.atomicAdd +func cAddInt64(addr *int64, delta int64) (old int64) + +func AddInt64(addr *int64, delta int64) (new int64) { + return cAddInt64(addr, delta) + delta +} From dc1fbbf796d9d18ff9520852d386e09f679bf1ac Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 16 Jun 2024 21:32:11 +0800 Subject: [PATCH 3/6] llgo:skipall --- cl/compile.go | 11 ++++++++--- cl/import.go | 16 +++++++++++++--- internal/build/build.go | 23 +++++++++++++++++------ internal/lib/sync/atomic/atomic.go | 2 +- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/cl/compile.go b/cl/compile.go index 3b631e69..2d20d234 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -100,10 +100,11 @@ func ignoreName(name string) bool { strings.HasPrefix(name, "arena.") || strings.HasPrefix(name, "maps.") || strings.HasPrefix(name, "time.") || strings.HasPrefix(name, "syscall.") || strings.HasPrefix(name, "os.") || strings.HasPrefix(name, "plugin.") || - strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "errors.") { + strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "errors.") || + strings.HasPrefix(name, "sync.") { return true // TODO(xsw) } - return inPkg(name, "runtime") || inPkg(name, "sync") + return inPkg(name, "runtime") } func inPkg(name, pkg string) bool { @@ -157,6 +158,8 @@ type context struct { inits []func() phis []func() + + skipall bool } func (p *context) inMain(instr ssa.Instruction) bool { @@ -1048,7 +1051,9 @@ func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) processPkg(ctx, ret, alt) ctx.skips = skips } - processPkg(ctx, ret, pkg) + if !ctx.skipall { + processPkg(ctx, ret, pkg) + } for len(ctx.inits) > 0 { inits := ctx.inits ctx.inits = nil diff --git a/cl/import.go b/cl/import.go index c1217778..72addadd 100644 --- a/cl/import.go +++ b/cl/import.go @@ -193,10 +193,12 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) { } } +// llgo:skip symbol1 symbol2 ... +// llgo:skipall func (p *context) collectSkipNames(line string) { const ( - skip = "//llgo:skip " - skip2 = "// llgo:skip " + skip = "//llgo:skip" + skip2 = "// llgo:skip" ) if strings.HasPrefix(line, skip2) { p.collectSkip(line, len(skip2)) @@ -206,7 +208,15 @@ func (p *context) collectSkipNames(line string) { } func (p *context) collectSkip(line string, prefix int) { - names := strings.Split(line[prefix:], " ") + line = line[prefix:] + if line == "all" { + p.skipall = true + return + } + if len(line) == 0 || line[0] != ' ' { + return + } + names := strings.Split(line[1:], " ") for _, name := range names { if name != "" { p.skips[name] = none{} diff --git a/internal/build/build.go b/internal/build/build.go index 552a71f1..9568246f 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -22,6 +22,7 @@ import ( "go/token" "go/types" "io" + "log" "os" "os/exec" "path" @@ -159,6 +160,10 @@ func Do(args []string, conf *Config) { var runtimeFiles []string if needRt { + // TODO(xsw): maybe we need trace runtime sometimes + llssa.SetDebug(0) + cl.SetDebug(0) + skip := make(map[string]bool) for _, v := range pkgs { skip[v.PkgPath] = true @@ -208,7 +213,7 @@ const ( 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, ssaBuildMode) + ssaProg, pkgs, errPkgs := allPkgs(imp, initial, ssaBuildMode, verbose) ssaProg.Build() for _, errPkg := range errPkgs { for _, err := range errPkg.Errors { @@ -394,7 +399,7 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) { func canSkipToBuild(pkgPath string) bool { switch pkgPath { - case "unsafe", "runtime", "errors", "sync", "sync/atomic": + case "unsafe", "runtime", "errors", "sync": return true default: return strings.HasPrefix(pkgPath, "internal/") || @@ -419,7 +424,7 @@ var hasAltPkg = map[string]none{ 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) { +func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode, verbose bool) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) { var fset *token.FileSet if len(initial) > 0 { fset = initial[0].Fset @@ -433,9 +438,12 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p var ssaPkg = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) if imp != nil { if _, ok := hasAltPkg[p.PkgPath]; ok { + if verbose { + log.Println("==> Patching", p.PkgPath) + } altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath if altPkg = imp(altPkgPath); altPkg != nil { // TODO(xsw): how to minimize import times - altSSA = createAltSSAPkg(prog, altPkg) + altSSA = createAltSSAPkg(prog, altPkg, verbose) } } } @@ -447,14 +455,17 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (p return } -func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package { +func createAltSSAPkg(prog *ssa.Program, alt *packages.Package, verbose bool) *ssa.Package { 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 { + if pkgPath := pkgTypes.Path(); prog.ImportedPackage(pkgPath) == nil { + if verbose { + log.Println("==> SSAPackage", pkgPath) + } prog.CreatePackage(pkgTypes, p.Syntax, p.TypesInfo, true) } } diff --git a/internal/lib/sync/atomic/atomic.go b/internal/lib/sync/atomic/atomic.go index f62c5356..42e74b7d 100644 --- a/internal/lib/sync/atomic/atomic.go +++ b/internal/lib/sync/atomic/atomic.go @@ -16,7 +16,7 @@ package atomic -// llgo:skip init +// llgo:skipall import ( _ "unsafe" ) From 9c8570b37d1ec3930637235fc4623b0b203f52d3 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 16 Jun 2024 22:47:57 +0800 Subject: [PATCH 4/6] buildAllPkgs fix --- internal/build/build.go | 48 +++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index 9568246f..d5398aba 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -156,7 +156,8 @@ func Do(args []string, conf *Config) { return nil } - pkgs := buildAllPkgs(prog, imp, initial, nil, mode, verbose) + progSSA := ssa.NewProgram(initial[0].Fset, ssaBuildMode) + pkgs := buildAllPkgs(prog, progSSA, imp, initial, nil, mode, verbose) var runtimeFiles []string if needRt { @@ -168,7 +169,7 @@ func Do(args []string, conf *Config) { for _, v := range pkgs { skip[v.PkgPath] = true } - dpkg := buildAllPkgs(prog, imp, rt[:1], skip, mode, verbose) + dpkg := buildAllPkgs(prog, progSSA, imp, rt[:1], skip, mode, verbose) for _, pkg := range dpkg { if !strings.HasSuffix(pkg.ExportFile, ".ll") { continue @@ -211,10 +212,9 @@ const ( ssaBuildMode = ssa.SanityCheckFunctions ) -func buildAllPkgs(prog llssa.Program, imp importer, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) { +func buildAllPkgs(prog llssa.Program, progSSA *ssa.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, ssaBuildMode, verbose) - ssaProg.Build() + pkgs, errPkgs := allPkgs(progSSA, imp, initial, verbose) for _, errPkg := range errPkgs { for _, err := range errPkg.Errors { fmt.Fprintln(os.Stderr, err) @@ -424,18 +424,12 @@ var hasAltPkg = map[string]none{ type importer = func(pkgPath string) *packages.Package -func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode, verbose bool) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) { - var fset *token.FileSet - if len(initial) > 0 { - fset = initial[0].Fset - } - - prog = ssa.NewProgram(fset, mode) +func allPkgs(prog *ssa.Program, imp importer, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) { packages.Visit(initial, nil, func(p *packages.Package) { if p.Types != nil && !p.IllTyped { var altPkg *packages.Package var altSSA *ssa.Package - var ssaPkg = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) + var ssaPkg = createSSAPkg(prog, p) if imp != nil { if _, ok := hasAltPkg[p.PkgPath]; ok { if verbose { @@ -443,7 +437,7 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode, ve } altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath if altPkg = imp(altPkgPath); altPkg != nil { // TODO(xsw): how to minimize import times - altSSA = createAltSSAPkg(prog, altPkg, verbose) + altSSA = createAltSSAPkg(prog, altPkg) } } } @@ -455,26 +449,28 @@ func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode, ve return } -func createAltSSAPkg(prog *ssa.Program, alt *packages.Package, verbose bool) *ssa.Package { - altPath := alt.Types.Path() - altSSA := prog.ImportedPackage(altPath) +func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package { + altSSA := prog.ImportedPackage(alt.PkgPath) if altSSA == nil { packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) { - pkgTypes := p.Types - if pkgTypes != nil && !p.IllTyped { - if pkgPath := pkgTypes.Path(); prog.ImportedPackage(pkgPath) == nil { - if verbose { - log.Println("==> SSAPackage", pkgPath) - } - prog.CreatePackage(pkgTypes, p.Syntax, p.TypesInfo, true) - } + if p.Types != nil && !p.IllTyped { + createSSAPkg(prog, p) } }) - altSSA = prog.ImportedPackage(altPath) + altSSA = prog.ImportedPackage(alt.PkgPath) } return altSSA } +func createSSAPkg(prog *ssa.Program, p *packages.Package) *ssa.Package { + pkgSSA := prog.ImportedPackage(p.PkgPath) + if pkgSSA == nil { + pkgSSA = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) + pkgSSA.Build() // TODO(xsw): build concurrently + } + return pkgSSA +} + var ( // TODO(xsw): complete build flags buildFlags = map[string]bool{ From df2f13c9b688050d60564207c175a484209b0da8 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 16 Jun 2024 23:07:42 +0800 Subject: [PATCH 5/6] patch runtime, sync (use llgo:skipall) --- cl/_testlibgo/atomic/in.go | 3 +- cl/_testlibgo/atomic/out.ll | 46 ++++++++++++++++++++++++++++++ cl/compile.go | 15 ++-------- internal/build/build.go | 4 ++- internal/lib/runtime/runtime.go | 22 ++++++++++++++ internal/lib/sync/atomic/atomic.go | 1 - internal/lib/sync/sync.go | 22 ++++++++++++++ 7 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 cl/_testlibgo/atomic/out.ll create mode 100644 internal/lib/runtime/runtime.go create mode 100644 internal/lib/sync/sync.go diff --git a/cl/_testlibgo/atomic/in.go b/cl/_testlibgo/atomic/in.go index be7974ac..c6879d7e 100644 --- a/cl/_testlibgo/atomic/in.go +++ b/cl/_testlibgo/atomic/in.go @@ -6,6 +6,5 @@ import ( func main() { var v int64 = 100 - atomic.AddInt64(&v, 1) - println(v) + println(atomic.AddInt64(&v, 1)) } diff --git a/cl/_testlibgo/atomic/out.ll b/cl/_testlibgo/atomic/out.ll new file mode 100644 index 00000000..2155a116 --- /dev/null +++ b/cl/_testlibgo/atomic/out.ll @@ -0,0 +1,46 @@ +; 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 @"sync/atomic.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 ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8) + store i64 100, ptr %2, align 4 + %3 = call i64 @"sync/atomic.AddInt64"(ptr %2, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %3) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + ret i32 0 +} + +declare void @"sync/atomic.init"() + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) + +declare i64 @"sync/atomic.AddInt64"(ptr, i64) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) diff --git a/cl/compile.go b/cl/compile.go index 2d20d234..b73e96ce 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -96,23 +96,12 @@ func ignoreName(name string) bool { return true } */ - if strings.HasPrefix(name, "internal/") || strings.HasPrefix(name, "crypto/") || + return strings.HasPrefix(name, "internal/") || strings.HasPrefix(name, "crypto/") || strings.HasPrefix(name, "arena.") || strings.HasPrefix(name, "maps.") || strings.HasPrefix(name, "time.") || strings.HasPrefix(name, "syscall.") || strings.HasPrefix(name, "os.") || strings.HasPrefix(name, "plugin.") || strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "errors.") || - strings.HasPrefix(name, "sync.") { - return true // TODO(xsw) - } - return inPkg(name, "runtime") -} - -func inPkg(name, pkg string) bool { - if len(name) > len(pkg) && strings.HasPrefix(name, pkg) { - c := name[len(pkg)] - return c == '.' || c == '/' - } - return false + strings.HasPrefix(name, "runtime/") } // ----------------------------------------------------------------------------- diff --git a/internal/build/build.go b/internal/build/build.go index d5398aba..caec4e85 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -399,7 +399,7 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) { func canSkipToBuild(pkgPath string) bool { switch pkgPath { - case "unsafe", "runtime", "errors", "sync": + case "unsafe", "errors": return true default: return strings.HasPrefix(pkgPath, "internal/") || @@ -419,7 +419,9 @@ type none struct{} var hasAltPkg = map[string]none{ "math": {}, + "sync": {}, "sync/atomic": {}, + "runtime": {}, } type importer = func(pkgPath string) *packages.Package diff --git a/internal/lib/runtime/runtime.go b/internal/lib/runtime/runtime.go new file mode 100644 index 00000000..e8492442 --- /dev/null +++ b/internal/lib/runtime/runtime.go @@ -0,0 +1,22 @@ +/* + * 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 runtime + +// llgo:skipall +import ( + _ "unsafe" +) diff --git a/internal/lib/sync/atomic/atomic.go b/internal/lib/sync/atomic/atomic.go index 42e74b7d..24c3ecb1 100644 --- a/internal/lib/sync/atomic/atomic.go +++ b/internal/lib/sync/atomic/atomic.go @@ -16,7 +16,6 @@ package atomic -// llgo:skipall import ( _ "unsafe" ) diff --git a/internal/lib/sync/sync.go b/internal/lib/sync/sync.go new file mode 100644 index 00000000..56822964 --- /dev/null +++ b/internal/lib/sync/sync.go @@ -0,0 +1,22 @@ +/* + * 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 sync + +// llgo:skipall +import ( + _ "unsafe" +) From 68a63bb280f9bc823a94fdc9617e32dd6ccdf925 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 16 Jun 2024 23:11:28 +0800 Subject: [PATCH 6/6] TestIgnoreName --- cl/builtin_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl/builtin_test.go b/cl/builtin_test.go index 9d3ee83d..bf5e12df 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -209,7 +209,7 @@ func TestIntVal(t *testing.T) { } func TestIgnoreName(t *testing.T) { - if !ignoreName("runtime.foo") || !ignoreName("runtime/foo") || !ignoreName("internal/abi") { + if !ignoreName("runtime/foo") || !ignoreName("internal/abi") { t.Fatal("ignoreName failed") } }