Merge pull request #179 from xushiwei/q

llgo/ssa: PyNewVar; pyLoad
This commit is contained in:
xushiwei
2024-05-15 18:49:10 +08:00
committed by GitHub
14 changed files with 177 additions and 39 deletions

View File

@@ -31,7 +31,7 @@ See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c) for
You can import a Python library in `llgo`!
And `llgo` can import any Python library into `llgo` through a program called `llpyg`. The currently imported packages include:
And you can import any Python library into `llgo` through a program called `llpyg`. The currently imported packages include:
* [sys](https://pkg.go.dev/github.com/goplus/llgo/py/sys)
* [os](https://pkg.go.dev/github.com/goplus/llgo/py/os)

View File

@@ -18,7 +18,5 @@ func main() {
py.List(3.0, 2.0, 1.0),
)
x := numpy.Add(a, b)
c.Printf(c.Str("a = %s\n"), a.Str().CStr())
c.Printf(c.Str("a = %s\n"), b.Str().CStr())
c.Printf(c.Str("a+b = %s\n"), x.Str().CStr())
}

View File

@@ -6,5 +6,5 @@ import (
)
func main() {
c.Printf(c.Str("pi = %f\n"), math.Pi)
c.Printf(c.Str("pi = %f\n"), math.Pi.Float64())
}

10
cl/_testpy/pi/in.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py/math"
)
func main() {
c.Printf(c.Str("pi = %f\n"), math.Pi.Float64())
}

49
cl/_testpy/pi/out.ll Normal file
View File

@@ -0,0 +1,49 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@0 = private unnamed_addr constant [9 x i8] c"pi = %f\0A\00", align 1
@__llgo_py.math = external global ptr
@1 = private unnamed_addr constant [3 x i8] c"pi\00", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
call void @"github.com/goplus/llgo/py/math.init"()
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main(i32 %0, ptr %1) {
_llgo_0:
call void @Py_Initialize()
store i32 %0, ptr @__llgo_argc, align 4
store ptr %1, ptr @__llgo_argv, align 8
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%2 = load ptr, ptr @__llgo_py.math, align 8
%3 = call ptr @PyObject_GetAttrString(ptr %2, ptr @1)
%4 = call double @PyFloat_AsDouble(ptr %3)
%5 = call i32 (ptr, ...) @printf(ptr @0, double %4)
ret void
}
declare void @"github.com/goplus/llgo/py/math.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @PyObject_GetAttrString(ptr, ptr)
declare double @PyFloat_AsDouble(ptr)
declare i32 @printf(ptr, ...)
declare void @Py_Initialize()

View File

@@ -226,5 +226,5 @@ func TestErrVarOf(t *testing.T) {
}
ssaPkg := &ssa.Package{Pkg: pkgTypes}
g := &ssa.Global{Pkg: ssaPkg}
ctx.varOf(g)
ctx.varOf(nil, g)
}

View File

@@ -176,7 +176,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, ssaMthd, false)
p.compileFuncDecl(pkg, ssaMthd)
}
}
}
@@ -185,7 +185,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
typ := gbl.Type()
name, vtype := p.varName(gbl.Pkg.Pkg, gbl)
if ignoreName(name) || checkCgo(gbl.Name()) {
if vtype == pyVar || ignoreName(name) || checkCgo(gbl.Name()) {
return
}
if debugInstr {
@@ -211,7 +211,7 @@ var (
argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8]))
)
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function, call bool) (llssa.Function, llssa.PyObjRef, int) {
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyObjRef, int) {
pkgTypes, name, ftype := p.funcName(f, true)
if ftype != goFunc {
/*
@@ -221,7 +221,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function, call bool)
return nil, pkg.NewPyFunc(fnName, f.Signature, call), pyFunc
}
*/
_ = call
return nil, nil, ignoredFunc
}
fn := pkg.FuncOf(name)
@@ -294,7 +293,7 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
pkg := p.pkg
fnName := pysymPrefix + mod + "." + name
if pyFn = pkg.PyObjOf(fnName); pyFn == nil {
pyFn = pkg.NewPyFunc(fnName, fn.Signature, true)
pyFn = pkg.PyNewFunc(fnName, fn.Signature, true)
return
}
}
@@ -372,7 +371,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
b.SetBlockEx(ret, llssa.AfterInit)
for _, modName := range modNames {
objs := mods[modName]
b.LoadPyModSyms(modName, objs...)
b.PyLoadModSyms(modName, objs...)
}
}
})
@@ -396,13 +395,13 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
jumpTo := p.jumpTo(jump)
modPath := p.pyMod
modName := pysymPrefix + modPath
modPtr := pkg.NewPyModVar(modName, true).Expr
modPtr := pkg.PyNewModVar(modName, true).Expr
mod := b.Load(modPtr)
cond := b.BinOp(token.NEQ, mod, prog.Null(mod.Type))
newBlk := p.fn.MakeBlock()
b.If(cond, jumpTo, newBlk)
b.SetBlock(newBlk)
b.Store(modPtr, b.ImportPyMod(modPath))
b.Store(modPtr, b.PyImportMod(modPath))
b.Jump(jumpTo)
}
return ret
@@ -805,7 +804,7 @@ func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn ll
// v.Pkg == nil: means auto generated function?
if v.Pkg == p.goPkg || v.Pkg == nil {
// function in this package
goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v, true)
goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v)
if kind != ignoredFunc {
return
}
@@ -832,8 +831,7 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
}
return pyFn.Expr
case *ssa.Global:
g := p.varOf(v)
return g.Expr
return p.varOf(b, v)
case *ssa.Const:
t := types.Default(v.Type())
return b.Const(v.Value, p.prog.Type(t, llssa.InGo))
@@ -924,7 +922,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
// Do not try to build generic (non-instantiated) functions.
continue
}
ctx.compileFuncDecl(ret, member, false)
ctx.compileFuncDecl(ret, member)
case *ssa.Type:
ctx.compileType(ret, member)
case *ssa.Global:

View File

@@ -359,24 +359,35 @@ const (
ignoredVar = iota
goVar = int(llssa.InGo)
cVar = int(llssa.InC)
pyVar = int(llssa.InPython)
)
func (p *context) varName(pkg *types.Package, v *ssa.Global) (vName string, vtype int) {
name := llssa.FullName(pkg, v.Name())
if v, ok := p.link[name]; ok {
if strings.HasPrefix(v, "py.") {
return v[3:], pyVar
}
return v, cVar
}
return name, goVar
}
func (p *context) varOf(v *ssa.Global) (ret llssa.Global) {
func (p *context) varOf(b llssa.Builder, v *ssa.Global) llssa.Expr {
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
pkg := p.pkg
name, vtype := p.varName(pkgTypes, v)
if ret = pkg.VarOf(name); ret == nil {
if vtype == pyVar {
if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule {
return b.PyNewVar(pysymPrefix+mod, name).Expr
}
panic("unreachable")
}
ret := pkg.VarOf(name)
if ret == nil {
ret = pkg.NewVar(name, v.Type(), llssa.Background(vtype))
}
return
return ret.Expr
}
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {

Binary file not shown.

View File

@@ -282,6 +282,29 @@ func (p Function) Block(idx int) BasicBlock {
// -----------------------------------------------------------------------------
type aPyGlobal struct {
Expr
}
type PyGlobal = *aPyGlobal
// PyNewVar creates a Python variable.
func (b Builder) PyNewVar(modName, name string) PyGlobal {
pkg := b.Func.Pkg
modPtr := pkg.PyNewModVar(modName, false).Expr
mod := b.Load(modPtr)
return &aPyGlobal{pyVarExpr(mod, name)}
}
func (b Builder) pyLoad(ptr Expr) Expr {
pkg := b.Func.Pkg
t := ptr.raw.Type.(*pyVarTy)
fn := pkg.pyFunc("PyObject_GetAttrString", b.Prog.tyGetAttrString())
return b.Call(fn, t.mod, b.CStr(t.name))
}
// -----------------------------------------------------------------------------
type aPyObjRef struct {
Expr
Obj Global
@@ -290,8 +313,8 @@ type aPyObjRef struct {
// PyObjRef represents a python object reference.
type PyObjRef = *aPyObjRef
// NewPyFunc creates a new python function.
func (p Package) NewPyFunc(name string, sig *types.Signature, doInit bool) PyObjRef {
// PyNewFunc creates a new python function.
func (p Package) PyNewFunc(name string, sig *types.Signature, doInit bool) PyObjRef {
if v, ok := p.pyobjs[name]; ok {
return v
}

View File

@@ -54,6 +54,26 @@ func (v Expr) Do(b Builder) Expr {
// -----------------------------------------------------------------------------
type pyVarTy struct {
mod Expr
name string
}
func (p pyVarTy) Underlying() types.Type {
panic("don't call")
}
func (p pyVarTy) String() string {
return "pyVar"
}
func pyVarExpr(mod Expr, name string) Expr {
tvar := &aType{raw: rawType{&pyVarTy{mod, name}}, kind: vkPyVarRef}
return Expr{Type: tvar}
}
// -----------------------------------------------------------------------------
type phisExprTy struct {
phis []llvm.Value
Type
@@ -68,7 +88,8 @@ func (p phisExprTy) String() string {
}
func phisExpr(t Type, phis []llvm.Value) Expr {
return Expr{Type: &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr}}
tphi := &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr}
return Expr{Type: tphi}
}
// -----------------------------------------------------------------------------
@@ -513,6 +534,9 @@ func (b Builder) Load(ptr Expr) Expr {
if debugInstr {
log.Printf("Load %v\n", ptr.impl)
}
if ptr.kind == vkPyVarRef {
return b.pyLoad(ptr)
}
telem := b.Prog.Elem(ptr.Type)
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
}

View File

@@ -146,6 +146,7 @@ type aProgram struct {
callOneArg *types.Signature
callFOArgs *types.Signature
loadPyModS *types.Signature
getAttrStr *types.Signature
paramObjPtr_ *types.Var
@@ -497,6 +498,7 @@ func (p Program) paramObjPtr() *types.Var {
return p.paramObjPtr_
}
// func(*char) *Object
func (p Program) tyImportPyModule() *types.Signature {
if p.pyImpTy == nil {
charPtr := types.NewPointer(types.Typ[types.Int8])
@@ -507,6 +509,7 @@ func (p Program) tyImportPyModule() *types.Signature {
return p.pyImpTy
}
// func(*Object) *Object
func (p Program) tyCallNoArgs() *types.Signature {
if p.callNoArgs == nil {
params := types.NewTuple(p.paramObjPtr())
@@ -515,6 +518,7 @@ func (p Program) tyCallNoArgs() *types.Signature {
return p.callNoArgs
}
// func(*Object, *Object) *Object
func (p Program) tyCallOneArg() *types.Signature {
if p.callOneArg == nil {
paramObjPtr := p.paramObjPtr()
@@ -525,6 +529,7 @@ func (p Program) tyCallOneArg() *types.Signature {
return p.callOneArg
}
// func(*Object, ...) *Object
func (p Program) tyCallFunctionObjArgs() *types.Signature {
if p.callFOArgs == nil {
paramObjPtr := p.paramObjPtr()
@@ -536,6 +541,7 @@ func (p Program) tyCallFunctionObjArgs() *types.Signature {
}
/*
// func(*Object, *Object, *Object) *Object
func (p Program) tyCall() *types.Signature {
if p.callArgs == nil {
paramObjPtr := p.paramObjPtr()
@@ -547,6 +553,7 @@ func (p Program) tyCall() *types.Signature {
}
*/
// 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)
@@ -559,6 +566,7 @@ func (p Program) tyListSetItem() *types.Signature {
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)
@@ -569,6 +577,7 @@ func (p Program) tyNewList() *types.Signature {
return p.pyNewList
}
// func(float64) *Object
func (p Program) tyFloatFromDouble() *types.Signature {
if p.callArgs == nil {
paramObjPtr := p.paramObjPtr()
@@ -580,29 +589,41 @@ func (p Program) tyFloatFromDouble() *types.Signature {
return p.callArgs
}
// func(*Object, ...)
func (p Program) tyLoadPyModSyms() *types.Signature {
if p.loadPyModS == nil {
objPtr := p.PyObjectPtr().raw.Type
paramObjPtr := types.NewParam(token.NoPos, nil, "mod", objPtr)
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).CallPyInit()
b.SetBlockEx(fn.Block(0), AtStart).callPyInit()
b.Dispose()
return true
}
return false
}
// NewPyModVar creates a new global variable for a Python module.
func (p Package) NewPyModVar(name string, doInit bool) Global {
// 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
}
@@ -617,18 +638,18 @@ func (p Package) NewPyModVar(name string, doInit bool) Global {
return g
}
// ImportPyMod imports a Python module.
func (b Builder) ImportPyMod(path string) Expr {
// PyImportMod imports a Python module.
func (b Builder) PyImportMod(path string) Expr {
pkg := b.Func.Pkg
fnImp := pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
return b.Call(fnImp, b.CStr(path))
}
// LoadPyModSyms loads python objects from specified module.
func (b Builder) LoadPyModSyms(modName string, objs ...PyObjRef) Expr {
// PyLoadModSyms loads python objects from specified module.
func (b Builder) PyLoadModSyms(modName string, objs ...PyObjRef) Expr {
pkg := b.Func.Pkg
fnLoad := pkg.pyFunc("llgoLoadPyModSyms", b.Prog.tyLoadPyModSyms())
modPtr := pkg.NewPyModVar(modName, false).Expr
modPtr := pkg.PyNewModVar(modName, false).Expr
mod := b.Load(modPtr)
args := make([]Expr, 1, len(objs)*2+2)
args[0] = mod
@@ -724,8 +745,8 @@ func (b Builder) PyFloat(fltVal Expr) (ret Expr) {
return b.Call(fn, fltVal)
}
// CallPyInit calls Py_Initialize.
func (b Builder) CallPyInit() (ret Expr) {
// callPyInit calls Py_Initialize.
func (b Builder) callPyInit() (ret Expr) {
fn := b.Func.Pkg.pyFunc("Py_Initialize", NoArgsNoRet)
return b.Call(fn)
}

View File

@@ -102,7 +102,9 @@ func TestCvtType(t *testing.T) {
func TestUserdefExpr(t *testing.T) {
b := &phisExprTy{}
c := &pyVarTy{}
_ = b.String()
_ = c.String()
test := func(a types.Type) {
defer func() {
if r := recover(); r == nil {
@@ -112,6 +114,7 @@ func TestUserdefExpr(t *testing.T) {
a.Underlying()
}
test(b)
test(c)
}
func TestAny(t *testing.T) {
@@ -143,12 +146,12 @@ func TestPyFunc(t *testing.T) {
prog.SetPython(py)
pkg := prog.NewPackage("bar", "foo/bar")
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
a := pkg.NewPyFunc("a", sig, false)
if pkg.NewPyFunc("a", sig, false) != a {
a := pkg.PyNewFunc("a", sig, false)
if pkg.PyNewFunc("a", sig, false) != a {
t.Fatal("NewPyFunc(a) failed")
}
foo := pkg.NewPyModVar("foo", false)
if pkg.NewPyModVar("foo", false) != foo {
foo := pkg.PyNewModVar("foo", false)
if pkg.PyNewModVar("foo", false) != foo {
t.Fatal("NewPyModVar(foo) failed")
}
}

View File

@@ -44,6 +44,7 @@ const (
vkFuncPtr
vkClosure
vkPyFuncRef
vkPyVarRef
vkTuple
vkSlice
vkPhisExpr = -1