From 915cdf2c2343e94288dd587ae80f10caa7692b42 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 23 Jun 2025 22:01:42 +0800 Subject: [PATCH] #1165 --- cl/_testdata/cpkg/in.go | 13 ++++++++++ cl/_testdata/cpkg/out.ll | 35 ++++++++++++++++++++++++++ cl/compile.go | 2 +- cl/import.go | 54 ++++++++++++++++++++++++---------------- internal/build/build.go | 8 +++--- internal/build/clean.go | 2 ++ 6 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 cl/_testdata/cpkg/in.go create mode 100644 cl/_testdata/cpkg/out.ll diff --git a/cl/_testdata/cpkg/in.go b/cl/_testdata/cpkg/in.go new file mode 100644 index 00000000..742e83df --- /dev/null +++ b/cl/_testdata/cpkg/in.go @@ -0,0 +1,13 @@ +package C + +func Xadd(a, b int) int { + return add(a, b) +} + +func Double(x float64) float64 { + return 2 * x +} + +func add(a, b int) int { + return a + b +} diff --git a/cl/_testdata/cpkg/out.ll b/cl/_testdata/cpkg/out.ll new file mode 100644 index 00000000..934dc700 --- /dev/null +++ b/cl/_testdata/cpkg/out.ll @@ -0,0 +1,35 @@ +; ModuleID = 'github.com/goplus/llgo/cl/_testdata/cpkg' +source_filename = "github.com/goplus/llgo/cl/_testdata/cpkg" + +@"github.com/goplus/llgo/cl/_testdata/cpkg.init$guard" = global i1 false, align 1 + +define double @Double(double %0) { +_llgo_0: + %1 = fmul double 2.000000e+00, %0 + ret double %1 +} + +define i64 @add(i64 %0, i64 %1) { +_llgo_0: + %2 = call i64 @"github.com/goplus/llgo/cl/_testdata/cpkg.add"(i64 %0, i64 %1) + ret i64 %2 +} + +define i64 @"github.com/goplus/llgo/cl/_testdata/cpkg.add"(i64 %0, i64 %1) { +_llgo_0: + %2 = add i64 %0, %1 + ret i64 %2 +} + +define void @"github.com/goplus/llgo/cl/_testdata/cpkg.init"() { +_llgo_0: + %0 = load i1, ptr @"github.com/goplus/llgo/cl/_testdata/cpkg.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"github.com/goplus/llgo/cl/_testdata/cpkg.init$guard", align 1 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} diff --git a/cl/compile.go b/cl/compile.go index e8c3fdcb..6f391f95 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -1005,7 +1005,7 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [ cgoSymbols: make([]string, 0, 128), } ctx.initPyModule() - ctx.initFiles(pkgPath, files) + ctx.initFiles(pkgPath, files, pkgName == "C") ctx.prog.SetPatch(ctx.patchType) ret.SetPatch(ctx.patchType) ret.SetResolveLinkname(ctx.resolveLinkname) diff --git a/cl/import.go b/cl/import.go index be3cc8c3..b70d0046 100644 --- a/cl/import.go +++ b/cl/import.go @@ -174,13 +174,18 @@ start: syms.initLinknames(p) } -func (p *context) initFiles(pkgPath string, files []*ast.File) { +func (p *context) initFiles(pkgPath string, files []*ast.File, cPkg bool) { for _, file := range files { for _, decl := range file.Decls { switch decl := decl.(type) { case *ast.FuncDecl: fullName, inPkgName := astFuncName(pkgPath, decl) - p.initLinknameByDoc(decl.Doc, fullName, inPkgName, false) + if !p.initLinknameByDoc(decl.Doc, fullName, inPkgName, false) && cPkg { + // package C (https://github.com/goplus/llgo/issues/1165) + if decl.Recv == nil && token.IsExported(inPkgName) { + p.prog.SetLinkname(fullName, strings.TrimPrefix(inPkgName, "X")) + } + } case *ast.GenDecl: switch decl.Tok { case token.VAR: @@ -266,51 +271,58 @@ func (p *context) collectSkip(line string, prefix int) { } } -func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar bool) { +func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar bool) bool { if doc != nil { for n := len(doc.List) - 1; n >= 0; n-- { line := doc.List[n].Text - found := p.initLinkname(line, func(name string) (_ string, _, ok bool) { + ret := p.initLinkname(line, func(name string) (_ string, _, ok bool) { return fullName, isVar, name == inPkgName }) - if !found { - break + if ret != unknownDirective { + return ret == hasLinkname } } } + return false } -func (p *context) initLinkname(line string, f func(inPkgName string) (fullName string, isVar, ok bool)) bool { +const ( + noDirective = iota + hasLinkname + unknownDirective = -1 +) + +func (p *context) initLinkname(line string, f func(inPkgName string) (fullName string, isVar, ok bool)) int { const ( - linkname = "//go:linkname " - llgolink = "//llgo:link " - llgolink2 = "// llgo:link " - exportName = "//export " - directive = "//go:" + linkname = "//go:linkname " + llgolink = "//llgo:link " + llgolink2 = "// llgo:link " + export = "//export " + directive = "//go:" ) if strings.HasPrefix(line, linkname) { p.initLink(line, len(linkname), f) - return true + return hasLinkname } else if strings.HasPrefix(line, llgolink2) { p.initLink(line, len(llgolink2), f) - return true + return hasLinkname } else if strings.HasPrefix(line, llgolink) { p.initLink(line, len(llgolink), f) - return true - } else if strings.HasPrefix(line, exportName) { - p.initCgoExport(line, len(exportName), f) - return true + return hasLinkname + } else if strings.HasPrefix(line, export) { + p.initCgoExport(line, len(export), f) + return hasLinkname } else if strings.HasPrefix(line, directive) { // skip unknown annotation but continue to parse the next annotation - return true + return unknownDirective } - return false + return noDirective } func (p *context) initCgoExport(line string, prefix int, f func(inPkgName string) (fullName string, isVar, ok bool)) { name := strings.TrimSpace(line[prefix:]) if fullName, _, ok := f(name); ok { - p.cgoExports[fullName] = name + p.cgoExports[fullName] = name // TODO(xsw): why not use prog.SetLinkname? } } diff --git a/internal/build/build.go b/internal/build/build.go index 4b47b3b1..3c45dac1 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -184,7 +184,7 @@ func Do(args []string, conf *Config) ([]Package, error) { prog := llssa.NewProgram(target) sizes := func(sizes types.Sizes, compiler, arch string) types.Sizes { if arch == "wasm" { - sizes = &types.StdSizes{4, 4} + sizes = &types.StdSizes{WordSize: 4, MaxAlign: 4} } return prog.TypeSizes(sizes) } @@ -803,7 +803,7 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) error { fmt.Fprintf(os.Stderr, "==> Export %s: %s\n", aPkg.PkgPath, pkg.ExportFile) } if IsCheckEnable() { - if err, msg := llcCheck(ctx.env, pkg.ExportFile); err != nil { + if msg, err := llcCheck(ctx.env, pkg.ExportFile); err != nil { fmt.Fprintf(os.Stderr, "==> lcc %v: %v\n%v\n", pkg.PkgPath, pkg.ExportFile, msg) } } @@ -811,7 +811,7 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) error { return nil } -func llcCheck(env *llvm.Env, exportFile string) (err error, msg string) { +func llcCheck(env *llvm.Env, exportFile string) (msg string, err error) { bin := filepath.Join(env.BinDir(), "llc") cmd := exec.Command(bin, "-filetype=null", exportFile) var buf bytes.Buffer @@ -904,6 +904,7 @@ func createSSAPkg(prog *ssa.Program, p *packages.Package, verbose bool) *ssa.Pac return pkgSSA } +/* var ( // TODO(xsw): complete build flags buildFlags = map[string]bool{ @@ -922,6 +923,7 @@ var ( "-ldflags": true, // --ldflags 'flag list': arguments to pass on each go tool link invocation } ) +*/ const llgoDebug = "LLGO_DEBUG" const llgoDbgSyms = "LLGO_DEBUG_SYMBOLS" diff --git a/internal/build/clean.go b/internal/build/clean.go index 71ca1a1f..31fecf18 100644 --- a/internal/build/clean.go +++ b/internal/build/clean.go @@ -26,12 +26,14 @@ import ( "github.com/goplus/llgo/internal/packages" ) +/* var ( // TODO(xsw): complete clean flags cleanFlags = map[string]bool{ "-v": false, // -v: print the paths of packages as they are clean } ) +*/ func Clean(patterns []string, conf *Config) { if conf.Goos == "" {