ssa/python.go

This commit is contained in:
xushiwei
2024-06-05 16:29:58 +08:00
parent 11b4de63ee
commit c48b39baab
4 changed files with 429 additions and 403 deletions

View File

@@ -218,17 +218,6 @@ func NewProgram(target *Target) Program {
}
}
// SetPython sets the Python package.
// Its type can be *types.Package or func() *types.Package.
func (p Program) SetPython(py any) {
switch v := py.(type) {
case *types.Package:
p.py = v
case func() *types.Package:
p.pyget = v
}
}
// SetRuntime sets the runtime.
// Its type can be *types.Package or func() *types.Package.
func (p Program) SetRuntime(runtime any) {
@@ -248,25 +237,12 @@ func (p Program) runtime() *types.Package {
return p.rt
}
func (p Program) python() *types.Package {
if p.py == nil {
p.py = p.pyget()
}
return p.py
}
func (p Program) rtNamed(name string) *types.Named {
t := p.runtime().Scope().Lookup(name).Type().(*types.Named)
t, _ = p.gocvt.cvtNamed(t)
return t
}
func (p Program) pyNamed(name string) *types.Named {
// TODO(xsw): does python type need to convert?
t := p.python().Scope().Lookup(name).Type().(*types.Named)
return t
}
func (p Program) rtType(name string) Type {
return p.rawType(p.rtNamed(name))
}
@@ -375,23 +351,6 @@ func (p Program) AbiTypePtrPtr() Type {
return p.abiTyPPtr
}
// PyObjectPtrPtr returns the **py.Object type.
func (p Program) PyObjectPtrPtr() Type {
if p.pyObjPPtr == nil {
p.pyObjPPtr = p.Pointer(p.PyObjectPtr())
}
return p.pyObjPPtr
}
// PyObjectPtr returns the *py.Object type.
func (p Program) PyObjectPtr() Type {
if p.pyObjPtr == nil {
objPtr := types.NewPointer(p.pyNamed("Object"))
p.pyObjPtr = p.rawType(objPtr)
}
return p.pyObjPtr
}
// Void returns void type.
func (p Program) Void() Type {
if p.voidTy == nil {
@@ -587,11 +546,6 @@ func (p Package) cFunc(fullName string, sig *types.Signature) Expr {
return p.NewFunc(fullName, sig, InC).Expr
}
func (p Package) pyFunc(fullName string, sig *types.Signature) Expr {
p.Prog.NeedPyInit = true
return p.NewFunc(fullName, sig, InC).Expr
}
func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
name := v.impl.Name()
prog := b.Prog
@@ -709,265 +663,3 @@ func (p *Package) WriteFile(file string) (err error) {
*/
// -----------------------------------------------------------------------------
func (p Program) paramObjPtr() *types.Var {
if p.paramObjPtr_ == nil {
objPtr := p.PyObjectPtr().raw.Type
p.paramObjPtr_ = types.NewParam(token.NoPos, nil, "", objPtr)
}
return p.paramObjPtr_
}
// func(*char) *Object
func (p Program) tyImportPyModule() *types.Signature {
if p.pyImpTy == nil {
charPtr := types.NewPointer(types.Typ[types.Int8])
params := types.NewTuple(types.NewParam(token.NoPos, nil, "", charPtr))
results := types.NewTuple(p.paramObjPtr())
p.pyImpTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.pyImpTy
}
// func(*Object) *Object
func (p Program) tyCallNoArgs() *types.Signature {
if p.callNoArgs == nil {
params := types.NewTuple(p.paramObjPtr())
p.callNoArgs = types.NewSignatureType(nil, nil, nil, params, params, false)
}
return p.callNoArgs
}
// func(*Object, *Object) *Object
func (p Program) tyCallOneArg() *types.Signature {
if p.callOneArg == nil {
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, paramObjPtr)
results := types.NewTuple(paramObjPtr)
p.callOneArg = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.callOneArg
}
// func(*Object, ...) *Object
func (p Program) tyCallFunctionObjArgs() *types.Signature {
if p.callFOArgs == nil {
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, VArg())
results := types.NewTuple(paramObjPtr)
p.callFOArgs = types.NewSignatureType(nil, nil, nil, params, results, true)
}
return p.callFOArgs
}
/*
// func(*Object, *Object, *Object) *Object
func (p Program) tyCall() *types.Signature {
if p.callArgs == nil {
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, paramObjPtr, paramObjPtr)
results := types.NewTuple(paramObjPtr)
p.callArgs = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.callArgs
}
*/
// func(*Object, uintptr, *Object) cint
func (p Program) tyListSetItem() *types.Signature {
if p.pyListSetI == nil {
paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type)
paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type)
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, paramUintptr, paramObjPtr)
results := types.NewTuple(paramCInt)
p.pyListSetI = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.pyListSetI
}
// func(uintptr) *Object
func (p Program) tyNewList() *types.Signature {
if p.pyNewList == nil {
paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type)
params := types.NewTuple(paramUintptr)
results := types.NewTuple(p.paramObjPtr())
p.pyNewList = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.pyNewList
}
// func(float64) *Object
func (p Program) tyFloatFromDouble() *types.Signature {
if p.floatFromDbl == nil {
paramObjPtr := p.paramObjPtr()
paramFloat := types.NewParam(token.NoPos, nil, "", p.Float64().raw.Type)
params := types.NewTuple(paramFloat)
results := types.NewTuple(paramObjPtr)
p.floatFromDbl = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.floatFromDbl
}
// func(*Object, ...)
func (p Program) tyLoadPyModSyms() *types.Signature {
if p.loadPyModS == nil {
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, VArg())
p.loadPyModS = types.NewSignatureType(nil, nil, nil, params, nil, true)
}
return p.loadPyModS
}
// func(*Objecg, *char) *Object
func (p Program) tyGetAttrString() *types.Signature {
if p.getAttrStr == nil {
charPtr := types.NewPointer(types.Typ[types.Int8])
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, types.NewParam(token.NoPos, nil, "", charPtr))
results := types.NewTuple(paramObjPtr)
p.getAttrStr = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.getAttrStr
}
// PyInit initializes Python for a main package.
func (p Package) PyInit() bool {
if fn := p.FuncOf("main"); fn != nil {
b := fn.NewBuilder()
b.SetBlockEx(fn.Block(0), AtStart, false).callPyInit()
b.Dispose()
return true
}
return false
}
// PyNewModVar creates a new global variable for a Python module.
func (p Package) PyNewModVar(name string, doInit bool) Global {
if v, ok := p.pymods[name]; ok {
return v
}
prog := p.Prog
objPtr := prog.PyObjectPtrPtr().raw.Type
g := p.NewVar(name, objPtr, InC)
if doInit {
g.Init(prog.Null(g.Type))
g.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
}
p.pymods[name] = g
return g
}
// PyImportMod imports a Python module.
func (b Builder) PyImportMod(path string) Expr {
fnImp := b.Pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
return b.Call(fnImp, b.CStr(path))
}
// PyLoadModSyms loads python objects from specified module.
func (b Builder) PyLoadModSyms(modName string, objs ...PyObjRef) Expr {
pkg := b.Pkg
fnLoad := pkg.pyFunc("llgoLoadPyModSyms", b.Prog.tyLoadPyModSyms())
modPtr := pkg.PyNewModVar(modName, false).Expr
mod := b.Load(modPtr)
args := make([]Expr, 1, len(objs)*2+2)
args[0] = mod
nbase := len(modName) + 1
for _, o := range objs {
fullName := o.impl.Name()
name := fullName[nbase:]
args = append(args, b.CStr(name))
args = append(args, o.Expr)
}
prog := b.Prog
args = append(args, prog.Null(prog.CStr()))
return b.Call(fnLoad, args...)
}
func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
prog := b.Prog
pkg := b.Pkg
fn = b.Load(fn)
sig := fn.raw.Type.(*types.Signature)
params := sig.Params()
n := params.Len()
switch n {
case 0:
call := pkg.pyFunc("PyObject_CallNoArgs", prog.tyCallNoArgs())
ret = b.Call(call, fn)
case 1:
if !sig.Variadic() {
call := pkg.pyFunc("PyObject_CallOneArg", prog.tyCallOneArg())
return b.Call(call, fn, args[0])
}
fallthrough
default:
call := pkg.pyFunc("PyObject_CallFunctionObjArgs", prog.tyCallFunctionObjArgs())
n = len(args)
callargs := make([]Expr, n+2)
callargs[0] = fn
copy(callargs[1:], args)
callargs[n+1] = prog.PyNull()
ret = b.Call(call, callargs...)
}
return
}
// PyNewList(n uintptr) *Object
func (b Builder) PyNewList(n Expr) (ret Expr) {
prog := b.Prog
fn := b.Pkg.pyFunc("PyList_New", prog.tyNewList())
return b.Call(fn, n)
}
// PyListSetItem(list *Object, index uintptr, item *Object) c.Int
func (b Builder) PyListSetItem(list, index, item Expr) (ret Expr) {
prog := b.Prog
fn := b.Pkg.pyFunc("PyList_SetItem", prog.tyListSetItem())
return b.Call(fn, list, index, item)
}
// PyList(args ...Expr) *Object
func (b Builder) PyList(args ...Expr) (ret Expr) {
prog := b.Prog
n := len(args)
uintPtr := prog.Uintptr()
list := b.PyNewList(prog.IntVal(uint64(n), uintPtr))
for i, arg := range args {
b.PyListSetItem(list, prog.IntVal(uint64(i), uintPtr), b.PyVal(arg))
}
return list
}
// PyVal(v any) *Object
func (b Builder) PyVal(v Expr) (ret Expr) {
switch t := v.raw.Type.(type) {
case *types.Basic:
switch t.Kind() {
case types.Float64:
return b.PyFloat(v)
default:
panic("PyVal: todo")
}
default:
return v
}
}
// PyFloat(fltVal float64) *Object
func (b Builder) PyFloat(fltVal Expr) (ret Expr) {
fn := b.Pkg.pyFunc("PyFloat_FromDouble", b.Prog.tyFloatFromDouble())
return b.Call(fn, fltVal)
}
// callPyInit calls Py_Initialize.
func (b Builder) callPyInit() (ret Expr) {
fn := b.Pkg.pyFunc("Py_Initialize", NoArgsNoRet)
return b.Call(fn)
}
var (
NoArgsNoRet = types.NewSignatureType(nil, nil, nil, nil, nil, false)
)
// -----------------------------------------------------------------------------