llgo/ssa: PyFunction; NewPyFunc
This commit is contained in:
12
cl/_testpy/callpy/in.go
Normal file
12
cl/_testpy/callpy/in.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/py"
|
||||||
|
"github.com/goplus/llgo/py/math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
x := math.Sqrt(py.Float(2))
|
||||||
|
c.Printf(c.Str("sqrt(2) = %f\n"), x.Float64())
|
||||||
|
}
|
||||||
0
cl/_testpy/callpy/out.ll
Normal file
0
cl/_testpy/callpy/out.ll
Normal file
@@ -211,19 +211,19 @@ 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, f *ssa.Function) llssa.Function {
|
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyFunction, int) {
|
||||||
pkgTypes, name, ftype := p.funcName(f, true)
|
pkgTypes, name, ftype := p.funcName(f, true)
|
||||||
if ftype != goFunc {
|
if ftype != goFunc {
|
||||||
if ftype == pyFunc {
|
if ftype == pyFunc {
|
||||||
// TODO(xsw): pyMod == ""
|
// TODO(xsw): pyMod == ""
|
||||||
fn := pysymPrefix + p.pyMod + "." + name
|
fnName := pysymPrefix + p.pyMod + "." + name
|
||||||
pkg.NewVar(fn, pkg.Prog.PyObjectPtrPtr().RawType(), llssa.InC)
|
return nil, pkg.NewPyFunc(fnName, f.Signature), pyFunc
|
||||||
}
|
}
|
||||||
return nil
|
return nil, nil, ignoredFunc
|
||||||
}
|
}
|
||||||
fn := pkg.FuncOf(name)
|
fn := pkg.FuncOf(name)
|
||||||
if fn != nil && fn.HasBody() {
|
if fn != nil && fn.HasBody() {
|
||||||
return fn
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
var sig = f.Signature
|
var sig = f.Signature
|
||||||
@@ -279,14 +279,20 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) llssa.Func
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return fn
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) (aFn llssa.Function, pyFn llssa.PyFunction, ftype int) {
|
||||||
_, name, ftype := p.funcName(fn, false)
|
_, name, ftype := p.funcName(fn, false)
|
||||||
if ftype == llgoInstr {
|
switch ftype {
|
||||||
|
case pyFunc:
|
||||||
|
pkg := p.pkg
|
||||||
|
if pyFn = pkg.PyFuncOf(name); pyFn == nil {
|
||||||
|
pyFn = pkg.NewPyFunc(name, fn.Signature)
|
||||||
|
}
|
||||||
|
case llgoInstr:
|
||||||
switch name {
|
switch name {
|
||||||
case "cstr":
|
case "cstr":
|
||||||
ftype = llgoCstr
|
ftype = llgoCstr
|
||||||
@@ -307,11 +313,14 @@ 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 {
|
default:
|
||||||
pkg := p.pkg
|
pkg := p.pkg
|
||||||
if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 {
|
if aFn = pkg.FuncOf(name); aFn == nil {
|
||||||
|
if len(fn.FreeVars) > 0 {
|
||||||
|
return nil, nil, ignoredFunc
|
||||||
|
}
|
||||||
sig := fn.Signature
|
sig := fn.Signature
|
||||||
ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -542,11 +551,13 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
ret = b.BuiltinCall(fn, args...)
|
ret = b.BuiltinCall(fn, args...)
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
fn, ftype := p.compileFunction(cv)
|
aFn, pyFn, ftype := p.compileFunction(cv)
|
||||||
switch ftype {
|
switch ftype {
|
||||||
case goFunc, cFunc:
|
case goFunc, cFunc:
|
||||||
args := p.compileValues(b, args, kind)
|
args := p.compileValues(b, args, kind)
|
||||||
ret = b.Call(fn.Expr, args...)
|
ret = b.Call(aFn.Expr, args...)
|
||||||
|
case pyFunc:
|
||||||
|
log.Panicln("pyFunc:", pyFn)
|
||||||
case llgoCstr:
|
case llgoCstr:
|
||||||
ret = cstr(b, args)
|
ret = cstr(b, args)
|
||||||
case llgoAdvance:
|
case llgoAdvance:
|
||||||
@@ -742,12 +753,13 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunction(v *ssa.Function) (llssa.Function, int) {
|
func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyFunction, kind 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, v); fn != nil {
|
goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v)
|
||||||
return fn, goFunc
|
if kind != ignoredFunc {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p.funcOf(v)
|
return p.funcOf(v)
|
||||||
@@ -766,8 +778,11 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
fn, _ := p.compileFunction(v)
|
aFn, pyFn, _ := p.compileFunction(v)
|
||||||
return fn.Expr
|
if aFn != nil {
|
||||||
|
return aFn.Expr
|
||||||
|
}
|
||||||
|
return pyFn.Expr
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
g := p.varOf(v)
|
g := p.varOf(v)
|
||||||
return g.Expr
|
return g.Expr
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestpy(t *testing.T) {
|
func TestFromTestpy(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "./_testpy", false)
|
cltest.FromDir(t, "callpy", "./_testpy", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestlibc(t *testing.T) {
|
func TestFromTestlibc(t *testing.T) {
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, strin
|
|||||||
return nil, v[2:], cFunc
|
return nil, v[2:], cFunc
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(v, "py.") {
|
if strings.HasPrefix(v, "py.") {
|
||||||
return nil, v[3:], pyFunc
|
return pkg, v[3:], pyFunc
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(v, "llgo.") {
|
if strings.HasPrefix(v, "llgo.") {
|
||||||
return nil, v[5:], llgoInstr
|
return nil, v[5:], llgoInstr
|
||||||
|
|||||||
71
ssa/decl.go
71
ssa/decl.go
@@ -18,6 +18,7 @@ package ssa
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
@@ -68,6 +69,23 @@ type aGlobal struct {
|
|||||||
// variable.
|
// variable.
|
||||||
type Global = *aGlobal
|
type Global = *aGlobal
|
||||||
|
|
||||||
|
// NewVar creates a new global variable.
|
||||||
|
func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
|
||||||
|
if v, ok := p.vars[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
t := p.Prog.Type(typ, bg)
|
||||||
|
gbl := llvm.AddGlobal(p.mod, t.ll, name)
|
||||||
|
ret := &aGlobal{Expr{gbl, t}}
|
||||||
|
p.vars[name] = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// VarOf returns a global variable by name.
|
||||||
|
func (p Package) VarOf(name string) Global {
|
||||||
|
return p.vars[name]
|
||||||
|
}
|
||||||
|
|
||||||
// Init initializes the global variable with the given value.
|
// Init initializes the global variable with the given value.
|
||||||
func (g Global) Init(v Expr) {
|
func (g Global) Init(v Expr) {
|
||||||
g.impl.SetInitializer(v.impl)
|
g.impl.SetInitializer(v.impl)
|
||||||
@@ -140,6 +158,31 @@ type aFunction struct {
|
|||||||
// Function represents a function or method.
|
// Function represents a function or method.
|
||||||
type Function = *aFunction
|
type Function = *aFunction
|
||||||
|
|
||||||
|
// NewFunc creates a new function.
|
||||||
|
func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function {
|
||||||
|
return p.NewFuncEx(name, sig, bg, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFuncEx creates a new function.
|
||||||
|
func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool) Function {
|
||||||
|
if v, ok := p.fns[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
t := p.Prog.FuncDecl(sig, bg)
|
||||||
|
if debugInstr {
|
||||||
|
log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars)
|
||||||
|
}
|
||||||
|
fn := llvm.AddFunction(p.mod, name, t.ll)
|
||||||
|
ret := newFunction(fn, t, p, p.Prog, hasFreeVars)
|
||||||
|
p.fns[name] = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncOf returns a function by name.
|
||||||
|
func (p Package) FuncOf(name string) Function {
|
||||||
|
return p.fns[name]
|
||||||
|
}
|
||||||
|
|
||||||
func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars bool) Function {
|
func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars bool) Function {
|
||||||
params, hasVArg := newParams(t, prog)
|
params, hasVArg := newParams(t, prog)
|
||||||
base := 0
|
base := 0
|
||||||
@@ -241,3 +284,31 @@ func (p Function) Block(idx int) BasicBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type aPyFunction struct {
|
||||||
|
Expr
|
||||||
|
Obj Global
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyFunction represents a python function.
|
||||||
|
type PyFunction = *aPyFunction
|
||||||
|
|
||||||
|
// NewPyFunc creates a new python function.
|
||||||
|
func (p Package) NewPyFunc(name string, sig *types.Signature) PyFunction {
|
||||||
|
if v, ok := p.pyfns[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
obj := p.NewVar(name, p.Prog.PyObjectPtrPtr().RawType(), InC)
|
||||||
|
ty := &aType{obj.ll, rawType{sig}, vkPyFunc}
|
||||||
|
expr := Expr{obj.impl, ty}
|
||||||
|
ret := &aPyFunction{expr, obj}
|
||||||
|
p.pyfns[name] = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyFuncOf returns a function by name.
|
||||||
|
func (p Package) PyFuncOf(name string) PyFunction {
|
||||||
|
return p.pyfns[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package ssa
|
|||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
"golang.org/x/tools/go/types/typeutil"
|
"golang.org/x/tools/go/types/typeutil"
|
||||||
@@ -260,8 +259,9 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
|||||||
gbls := make(map[string]Global)
|
gbls := make(map[string]Global)
|
||||||
fns := make(map[string]Function)
|
fns := make(map[string]Function)
|
||||||
stubs := make(map[string]Function)
|
stubs := make(map[string]Function)
|
||||||
|
pyfns := make(map[string]PyFunction)
|
||||||
p.needRuntime = false
|
p.needRuntime = false
|
||||||
return &aPackage{mod, gbls, fns, stubs, p}
|
return &aPackage{mod, gbls, fns, stubs, pyfns, p}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PyObjectPtrPtr returns the **py.Object type.
|
// PyObjectPtrPtr returns the **py.Object type.
|
||||||
@@ -365,6 +365,7 @@ type aPackage struct {
|
|||||||
vars map[string]Global
|
vars map[string]Global
|
||||||
fns map[string]Function
|
fns map[string]Function
|
||||||
stubs map[string]Function
|
stubs map[string]Function
|
||||||
|
pyfns map[string]PyFunction
|
||||||
Prog Program
|
Prog Program
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,40 +378,6 @@ func (p Package) NewConst(name string, val constant.Value) NamedConst {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NewVar creates a new global variable.
|
|
||||||
func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
|
|
||||||
t := p.Prog.Type(typ, bg)
|
|
||||||
gbl := llvm.AddGlobal(p.mod, t.ll, name)
|
|
||||||
ret := &aGlobal{Expr{gbl, t}}
|
|
||||||
p.vars[name] = ret
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// VarOf returns a global variable by name.
|
|
||||||
func (p Package) VarOf(name string) Global {
|
|
||||||
return p.vars[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFunc creates a new function.
|
|
||||||
func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function {
|
|
||||||
return p.NewFuncEx(name, sig, bg, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFuncEx creates a new function.
|
|
||||||
func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool) Function {
|
|
||||||
if v, ok := p.fns[name]; ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
t := p.Prog.FuncDecl(sig, bg)
|
|
||||||
if debugInstr {
|
|
||||||
log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars)
|
|
||||||
}
|
|
||||||
fn := llvm.AddFunction(p.mod, name, t.ll)
|
|
||||||
ret := newFunction(fn, t, p, p.Prog, hasFreeVars)
|
|
||||||
p.fns[name] = ret
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Package) rtFunc(fnName string) Expr {
|
func (p Package) rtFunc(fnName string) Expr {
|
||||||
fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
||||||
name := FullName(fn.Pkg(), fnName)
|
name := FullName(fn.Pkg(), fnName)
|
||||||
@@ -456,11 +423,6 @@ func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
|||||||
return b.aggregateValue(prog.rawType(t), v.impl, nilVal)
|
return b.aggregateValue(prog.rawType(t), v.impl, nilVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncOf returns a function by name.
|
|
||||||
func (p Package) FuncOf(name string) Function {
|
|
||||||
return p.fns[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// String returns a string representation of the package.
|
// String returns a string representation of the package.
|
||||||
@@ -521,6 +483,13 @@ func (p Program) tyImportPyModule() *types.Signature {
|
|||||||
return p.pyImpTy
|
return p.pyImpTy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImportPyMod imports a Python module.
|
||||||
|
func (b Builder) ImportPyMod(path string) Expr {
|
||||||
|
pkg := b.Func.Pkg
|
||||||
|
fnImp := pkg.cpyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
|
||||||
|
return b.Call(fnImp, b.CStr(path))
|
||||||
|
}
|
||||||
|
|
||||||
// NewPyModVar creates a new global variable for a Python module.
|
// NewPyModVar creates a new global variable for a Python module.
|
||||||
func (p Package) NewPyModVar(name string) Global {
|
func (p Package) NewPyModVar(name string) Global {
|
||||||
prog := p.Prog
|
prog := p.Prog
|
||||||
@@ -531,11 +500,4 @@ func (p Package) NewPyModVar(name string) Global {
|
|||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPyMod imports a Python module.
|
|
||||||
func (b Builder) ImportPyMod(path string) Expr {
|
|
||||||
pkg := b.Func.Pkg
|
|
||||||
fnImp := pkg.cpyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
|
|
||||||
return b.Call(fnImp, b.CStr(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ const (
|
|||||||
vkFuncDecl
|
vkFuncDecl
|
||||||
vkFuncPtr
|
vkFuncPtr
|
||||||
vkClosure
|
vkClosure
|
||||||
|
vkPyFunc
|
||||||
vkTuple
|
vkTuple
|
||||||
vkPhisExpr = -1
|
vkPhisExpr = -1
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user