From c93fce87da4749d60480c2a9cb896a37b0a6e76f Mon Sep 17 00:00:00 2001 From: xushiwei Date: Tue, 7 May 2024 15:35:37 +0800 Subject: [PATCH] cl: initLinkname support //llgo:link --- c/c.go | 2 +- cl/compile.go | 26 +++++++++++---------- cl/compile_test.go | 6 +++++ cl/import.go | 58 +++++++++++++++++++++++++++++++--------------- ssa/type_cvt.go | 3 ++- 5 files changed, 62 insertions(+), 33 deletions(-) diff --git a/c/c.go b/c/c.go index 34a1c171..b10248ac 100644 --- a/c/c.go +++ b/c/c.go @@ -44,7 +44,7 @@ func Str(string) *Char func Advance(ptr Pointer, offset int) Pointer // llgo:link Index llgo.index -// func Index[T any, I integer](ptr *T, offset I) T { return *ptr } +func Index[T any, I integer](ptr *T, offset I) T { return *ptr } //go:linkname Alloca llgo.alloca func Alloca(size uintptr) Pointer diff --git a/cl/compile.go b/cl/compile.go index 4170a4c4..e3c37be3 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -170,7 +170,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) { for i, n := 0, mthds.Len(); i < n; i++ { mthd := mthds.At(i) if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil { - p.compileFuncDecl(pkg, mthd.Obj().Pkg(), ssaMthd) + p.compileFuncDecl(pkg, ssaMthd) } } } @@ -205,8 +205,8 @@ var ( argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8])) ) -func (p *context) compileFuncDecl(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) llssa.Function { - name, ftype := p.funcName(pkgTypes, f, true) +func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) llssa.Function { + pkgTypes, name, ftype := p.funcName(f, true) if ftype != goFunc { return nil } @@ -271,9 +271,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, pkgTypes *types.Package, f // funcOf returns a function by name and set ftype = goFunc, cFunc, etc. // or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc. func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) { - pkgTypes := p.ensureLoaded(fn.Pkg.Pkg) - pkg := p.pkg - name, ftype := p.funcName(pkgTypes, fn, false) + _, name, ftype := p.funcName(fn, false) if ftype == llgoInstr { switch name { case "cstr": @@ -289,9 +287,12 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) { default: panic("unknown llgo instruction: " + name) } - } else if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 { - sig := fn.Signature - ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false) + } else { + pkg := p.pkg + if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 { + sig := fn.Signature + ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false) + } } return } @@ -667,7 +668,7 @@ func (p *context) compileFunction(v *ssa.Function) (llssa.Function, int) { // v.Pkg == nil: means auto generated function? if v.Pkg == p.goPkg || v.Pkg == nil { // function in this package - if fn := p.compileFuncDecl(p.pkg, p.goTyps, v); fn != nil { + if fn := p.compileFuncDecl(p.pkg, v); fn != nil { return fn, goFunc } } @@ -776,11 +777,12 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll member := m.val switch member := member.(type) { case *ssa.Function: - if member.TypeParams() != nil { + if member.TypeParams() != nil || member.TypeArgs() != nil { + // TODO(xsw): don't compile generic functions // Do not try to build generic (non-instantiated) functions. continue } - ctx.compileFuncDecl(ret, member.Pkg.Pkg, member) + ctx.compileFuncDecl(ret, member) case *ssa.Type: ctx.compileType(ret, member) case *ssa.Global: diff --git a/cl/compile_test.go b/cl/compile_test.go index b9c3443f..f64b60c6 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -28,6 +28,12 @@ func testCompile(t *testing.T, src, expected string) { cltest.TestCompileEx(t, src, "foo.go", expected) } +/* +func TestFromTestlibc(t *testing.T) { + cltest.FromDir(t, "argv", "./_testlibc", false) +} +*/ + func TestFromTestrt(t *testing.T) { cltest.FromDir(t, "", "./_testrt", true) } diff --git a/cl/import.go b/cl/import.go index 8f5f149f..67bd7c64 100644 --- a/cl/import.go +++ b/cl/import.go @@ -148,18 +148,28 @@ func (p *context) initLinknameByPos(fset *token.FileSet, pos token.Pos, pkgPath func (p *context) initLinkname(pkgPath, line string, isVar bool) { const ( - linkname = "//go:linkname " + linkname = "//go:linkname " + llgolink = "//llgo:link " + llgolink2 = "// llgo:link " ) if strings.HasPrefix(line, linkname) { - text := strings.TrimSpace(line[len(linkname):]) - if idx := strings.IndexByte(text, ' '); idx > 0 { - link := strings.TrimLeft(text[idx+1:], " ") - if isVar || strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr - name := pkgPath + "." + text[:idx] - p.link[name] = link - } else { - panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf") - } + p.initLink(pkgPath, line, len(linkname), isVar) + } else if strings.HasPrefix(line, llgolink2) { + p.initLink(pkgPath, line, len(llgolink2), isVar) + } else if strings.HasPrefix(line, llgolink) { + p.initLink(pkgPath, line, len(llgolink), isVar) + } +} + +func (p *context) initLink(pkgPath string, line string, prefix int, isVar bool) { + text := strings.TrimSpace(line[prefix:]) + if idx := strings.IndexByte(text, ' '); idx > 0 { + link := strings.TrimLeft(text[idx+1:], " ") + if isVar || strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr + name := pkgPath + "." + text[:idx] + p.link[name] = link + } else { + panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf") } } } @@ -205,21 +215,31 @@ const ( llgoAdvance = llgoInstrBase + 4 ) -func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (string, int) { - name := funcName(pkg, fn) - if ignore && ignoreName(name) || checkCgo(fn.Name()) { - return name, ignoredFunc +func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { + var pkg *types.Package + var orgName string + if origin := fn.Origin(); origin != nil { + pkg = origin.Pkg.Pkg + p.ensureLoaded(pkg) + orgName = funcName(pkg, origin) + } else { + pkg = fn.Pkg.Pkg + p.ensureLoaded(pkg) + orgName = funcName(pkg, fn) + if ignore && ignoreName(orgName) || checkCgo(fn.Name()) { + return nil, orgName, ignoredFunc + } } - if v, ok := p.link[name]; ok { + if v, ok := p.link[orgName]; ok { if strings.HasPrefix(v, "C.") { - return v[2:], cFunc + return nil, v[2:], cFunc } if strings.HasPrefix(v, "llgo.") { - return v[5:], llgoInstr + return nil, v[5:], llgoInstr } - return v, goFunc + return pkg, v, goFunc } - return name, goFunc + return pkg, funcName(pkg, fn), goFunc } const ( diff --git a/ssa/type_cvt.go b/ssa/type_cvt.go index 76f9aae0..d6691f1e 100644 --- a/ssa/type_cvt.go +++ b/ssa/type_cvt.go @@ -17,6 +17,7 @@ package ssa import ( + "fmt" "go/token" "go/types" "unsafe" @@ -100,7 +101,7 @@ func (p goTypes) cvtType(typ types.Type) (raw types.Type, cvt bool) { return types.NewChan(t.Dir(), elem), true } default: - panic("unreachable") + panic(fmt.Sprintf("cvtType: unexpected type - %T", typ)) } return typ, false }