cl: initLinkname support //llgo:link
This commit is contained in:
2
c/c.go
2
c/c.go
@@ -44,7 +44,7 @@ func Str(string) *Char
|
|||||||
func Advance(ptr Pointer, offset int) Pointer
|
func Advance(ptr Pointer, offset int) Pointer
|
||||||
|
|
||||||
// llgo:link Index llgo.index
|
// 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
|
//go:linkname Alloca llgo.alloca
|
||||||
func Alloca(size uintptr) Pointer
|
func Alloca(size uintptr) Pointer
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
|||||||
for i, n := 0, mthds.Len(); i < n; i++ {
|
for i, n := 0, mthds.Len(); i < n; i++ {
|
||||||
mthd := mthds.At(i)
|
mthd := mthds.At(i)
|
||||||
if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil {
|
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]))
|
argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8]))
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *context) compileFuncDecl(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) llssa.Function {
|
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) llssa.Function {
|
||||||
name, ftype := p.funcName(pkgTypes, f, true)
|
pkgTypes, name, ftype := p.funcName(f, true)
|
||||||
if ftype != goFunc {
|
if ftype != goFunc {
|
||||||
return nil
|
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.
|
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
||||||
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
||||||
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
||||||
pkgTypes := p.ensureLoaded(fn.Pkg.Pkg)
|
_, name, ftype := p.funcName(fn, false)
|
||||||
pkg := p.pkg
|
|
||||||
name, ftype := p.funcName(pkgTypes, fn, false)
|
|
||||||
if ftype == llgoInstr {
|
if ftype == llgoInstr {
|
||||||
switch name {
|
switch name {
|
||||||
case "cstr":
|
case "cstr":
|
||||||
@@ -289,9 +287,12 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
|||||||
default:
|
default:
|
||||||
panic("unknown llgo instruction: " + name)
|
panic("unknown llgo instruction: " + name)
|
||||||
}
|
}
|
||||||
} else if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 {
|
} else {
|
||||||
sig := fn.Signature
|
pkg := p.pkg
|
||||||
ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 {
|
||||||
|
sig := fn.Signature
|
||||||
|
ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -667,7 +668,7 @@ func (p *context) compileFunction(v *ssa.Function) (llssa.Function, int) {
|
|||||||
// v.Pkg == nil: means auto generated function?
|
// v.Pkg == nil: means auto generated function?
|
||||||
if v.Pkg == p.goPkg || v.Pkg == nil {
|
if v.Pkg == p.goPkg || v.Pkg == nil {
|
||||||
// function in this package
|
// 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
|
return fn, goFunc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -776,11 +777,12 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
member := m.val
|
member := m.val
|
||||||
switch member := member.(type) {
|
switch member := member.(type) {
|
||||||
case *ssa.Function:
|
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.
|
// Do not try to build generic (non-instantiated) functions.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ctx.compileFuncDecl(ret, member.Pkg.Pkg, member)
|
ctx.compileFuncDecl(ret, member)
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ctx.compileType(ret, member)
|
ctx.compileType(ret, member)
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ func testCompile(t *testing.T, src, expected string) {
|
|||||||
cltest.TestCompileEx(t, src, "foo.go", expected)
|
cltest.TestCompileEx(t, src, "foo.go", expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func TestFromTestlibc(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "argv", "./_testlibc", false)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func TestFromTestrt(t *testing.T) {
|
func TestFromTestrt(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "./_testrt", true)
|
cltest.FromDir(t, "", "./_testrt", true)
|
||||||
}
|
}
|
||||||
|
|||||||
58
cl/import.go
58
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) {
|
func (p *context) initLinkname(pkgPath, line string, isVar bool) {
|
||||||
const (
|
const (
|
||||||
linkname = "//go:linkname "
|
linkname = "//go:linkname "
|
||||||
|
llgolink = "//llgo:link "
|
||||||
|
llgolink2 = "// llgo:link "
|
||||||
)
|
)
|
||||||
if strings.HasPrefix(line, linkname) {
|
if strings.HasPrefix(line, linkname) {
|
||||||
text := strings.TrimSpace(line[len(linkname):])
|
p.initLink(pkgPath, line, len(linkname), isVar)
|
||||||
if idx := strings.IndexByte(text, ' '); idx > 0 {
|
} else if strings.HasPrefix(line, llgolink2) {
|
||||||
link := strings.TrimLeft(text[idx+1:], " ")
|
p.initLink(pkgPath, line, len(llgolink2), isVar)
|
||||||
if isVar || strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr
|
} else if strings.HasPrefix(line, llgolink) {
|
||||||
name := pkgPath + "." + text[:idx]
|
p.initLink(pkgPath, line, len(llgolink), isVar)
|
||||||
p.link[name] = link
|
}
|
||||||
} else {
|
}
|
||||||
panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf")
|
|
||||||
}
|
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
|
llgoAdvance = llgoInstrBase + 4
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (string, int) {
|
func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) {
|
||||||
name := funcName(pkg, fn)
|
var pkg *types.Package
|
||||||
if ignore && ignoreName(name) || checkCgo(fn.Name()) {
|
var orgName string
|
||||||
return name, ignoredFunc
|
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.") {
|
if strings.HasPrefix(v, "C.") {
|
||||||
return v[2:], cFunc
|
return nil, v[2:], cFunc
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(v, "llgo.") {
|
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 (
|
const (
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@@ -100,7 +101,7 @@ func (p goTypes) cvtType(typ types.Type) (raw types.Type, cvt bool) {
|
|||||||
return types.NewChan(t.Dir(), elem), true
|
return types.NewChan(t.Dir(), elem), true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic(fmt.Sprintf("cvtType: unexpected type - %T", typ))
|
||||||
}
|
}
|
||||||
return typ, false
|
return typ, false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user