@@ -22,6 +22,10 @@ import (
|
||||
"github.com/goplus/llgo/cl/cltest"
|
||||
)
|
||||
|
||||
func TestFromTestpy(t *testing.T) {
|
||||
cltest.FromDir(t, "", "../cl/_testpy", false)
|
||||
}
|
||||
|
||||
func TestFromTestrt(t *testing.T) {
|
||||
cltest.FromDir(t, "", "../cl/_testrt", true)
|
||||
}
|
||||
|
||||
93
ssa/decl.go
93
ssa/decl.go
@@ -18,6 +18,7 @@ package ssa
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/goplus/llvm"
|
||||
@@ -68,6 +69,23 @@ type aGlobal struct {
|
||||
// variable.
|
||||
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.
|
||||
func (g Global) Init(v Expr) {
|
||||
g.impl.SetInitializer(v.impl)
|
||||
@@ -140,6 +158,31 @@ type aFunction struct {
|
||||
// Function represents a function or method.
|
||||
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 {
|
||||
params, hasVArg := newParams(t, prog)
|
||||
base := 0
|
||||
@@ -212,22 +255,60 @@ func (p Function) MakeBody(nblk int) Builder {
|
||||
|
||||
// MakeBlocks creates nblk basic blocks for the function.
|
||||
func (p Function) MakeBlocks(nblk int) []BasicBlock {
|
||||
if p.blks == nil {
|
||||
n := len(p.blks)
|
||||
if n == 0 {
|
||||
p.blks = make([]BasicBlock, 0, nblk)
|
||||
}
|
||||
n := len(p.blks)
|
||||
f := p.impl
|
||||
for i := 0; i < nblk; i++ {
|
||||
label := "_llgo_" + strconv.Itoa(i)
|
||||
blk := llvm.AddBasicBlock(f, label)
|
||||
p.blks = append(p.blks, &aBasicBlock{blk, p, n + i})
|
||||
p.addBlock(n + i)
|
||||
}
|
||||
return p.blks[n:]
|
||||
}
|
||||
|
||||
func (p Function) addBlock(idx int) BasicBlock {
|
||||
label := "_llgo_" + strconv.Itoa(idx)
|
||||
blk := llvm.AddBasicBlock(p.impl, label)
|
||||
ret := &aBasicBlock{blk, p, idx}
|
||||
p.blks = append(p.blks, ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
// MakeBlock creates a new basic block for the function.
|
||||
func (p Function) MakeBlock() BasicBlock {
|
||||
return p.addBlock(len(p.blks))
|
||||
}
|
||||
|
||||
// Block returns the ith basic block of the function.
|
||||
func (p Function) Block(idx int) BasicBlock {
|
||||
return p.blks[idx]
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -1204,7 +1204,6 @@ func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
|
||||
// t4 = t3()
|
||||
// t7 = invoke t5.Println(...t6)
|
||||
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||
prog := b.Prog
|
||||
if debugInstr {
|
||||
var b bytes.Buffer
|
||||
name := fn.impl.Name()
|
||||
@@ -1219,11 +1218,16 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||
}
|
||||
log.Println(b.String())
|
||||
}
|
||||
var kind = fn.kind
|
||||
if kind == vkPyFunc {
|
||||
return b.pyCall(fn, args)
|
||||
}
|
||||
var ll llvm.Type
|
||||
var data Expr
|
||||
var sig *types.Signature
|
||||
var prog = b.Prog
|
||||
var raw = fn.raw.Type
|
||||
switch fn.kind {
|
||||
switch kind {
|
||||
case vkClosure:
|
||||
data = b.Field(fn, 1)
|
||||
fn = b.Field(fn, 0)
|
||||
|
||||
171
ssa/package.go
171
ssa/package.go
@@ -19,13 +19,13 @@ package ssa
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
|
||||
"github.com/goplus/llvm"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
)
|
||||
|
||||
const (
|
||||
PkgPython = "github.com/goplus/llgo/py"
|
||||
PkgRuntime = "github.com/goplus/llgo/internal/runtime"
|
||||
)
|
||||
|
||||
@@ -103,6 +103,9 @@ type aProgram struct {
|
||||
rt *types.Package
|
||||
rtget func() *types.Package
|
||||
|
||||
py *types.Package
|
||||
pyget func() *types.Package
|
||||
|
||||
target *Target
|
||||
td llvm.TargetData
|
||||
// tm llvm.TargetMachine
|
||||
@@ -131,8 +134,15 @@ type aProgram struct {
|
||||
uintptrTy Type
|
||||
intTy Type
|
||||
f64Ty Type
|
||||
pyObjPtr Type
|
||||
pyObjPPtr Type
|
||||
|
||||
pyImpTy *types.Signature
|
||||
callNoArg *types.Signature
|
||||
callOneArg *types.Signature
|
||||
|
||||
needRuntime bool
|
||||
needPyInit bool
|
||||
}
|
||||
|
||||
// A Program presents a program.
|
||||
@@ -158,6 +168,17 @@ func NewProgram(target *Target) Program {
|
||||
return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td, named: make(map[string]llvm.Type)}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -182,12 +203,25 @@ 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))
|
||||
}
|
||||
@@ -228,8 +262,26 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
||||
gbls := make(map[string]Global)
|
||||
fns := make(map[string]Function)
|
||||
stubs := make(map[string]Function)
|
||||
pyfns := make(map[string]PyFunction)
|
||||
p.needRuntime = false
|
||||
return &aPackage{mod, gbls, fns, stubs, p}
|
||||
return &aPackage{mod, gbls, fns, stubs, pyfns, p}
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -316,6 +368,7 @@ type aPackage struct {
|
||||
vars map[string]Global
|
||||
fns map[string]Function
|
||||
stubs map[string]Function
|
||||
pyfns map[string]PyFunction
|
||||
Prog Program
|
||||
}
|
||||
|
||||
@@ -328,40 +381,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 {
|
||||
fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
||||
name := FullName(fn.Pkg(), fnName)
|
||||
@@ -369,6 +388,11 @@ func (p Package) rtFunc(fnName string) Expr {
|
||||
return p.NewFunc(name, sig, InGo).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
|
||||
@@ -402,11 +426,6 @@ func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
||||
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.
|
||||
@@ -455,3 +474,73 @@ func (p *Package) WriteFile(file string) (err error) {
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
func (p Program) tyImportPyModule() *types.Signature {
|
||||
if p.pyImpTy == nil {
|
||||
charPtr := types.NewPointer(types.Typ[types.Int8])
|
||||
objPtr := p.PyObjectPtr().raw.Type
|
||||
params := types.NewTuple(types.NewParam(token.NoPos, nil, "", charPtr))
|
||||
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", objPtr))
|
||||
p.pyImpTy = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||
}
|
||||
return p.pyImpTy
|
||||
}
|
||||
|
||||
func (p Program) tyCallNoArg() *types.Signature {
|
||||
if p.callNoArg == nil {
|
||||
objPtr := p.PyObjectPtr().raw.Type
|
||||
paramObjPtr := types.NewParam(token.NoPos, nil, "", objPtr)
|
||||
params := types.NewTuple(paramObjPtr)
|
||||
p.callNoArg = types.NewSignatureType(nil, nil, nil, params, params, false)
|
||||
}
|
||||
return p.callNoArg
|
||||
}
|
||||
|
||||
func (p Program) tyCallOneArg() *types.Signature {
|
||||
if p.callOneArg == nil {
|
||||
objPtr := p.PyObjectPtr().raw.Type
|
||||
paramObjPtr := types.NewParam(token.NoPos, nil, "", objPtr)
|
||||
params := types.NewTuple(paramObjPtr, paramObjPtr)
|
||||
results := types.NewTuple(paramObjPtr)
|
||||
p.callOneArg = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||
}
|
||||
return p.callOneArg
|
||||
}
|
||||
|
||||
// ImportPyMod imports a Python module.
|
||||
func (b Builder) ImportPyMod(path string) Expr {
|
||||
pkg := b.Func.Pkg
|
||||
fnImp := pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
|
||||
return b.Call(fnImp, b.CStr(path))
|
||||
}
|
||||
|
||||
// NewPyModVar creates a new global variable for a Python module.
|
||||
func (p Package) NewPyModVar(name string) Global {
|
||||
prog := p.Prog
|
||||
objPtr := prog.PyObjectPtrPtr().raw.Type
|
||||
g := p.NewVar(name, objPtr, InC)
|
||||
g.Init(prog.Null(g.Type))
|
||||
g.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
||||
return g
|
||||
}
|
||||
|
||||
func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
|
||||
prog := b.Prog
|
||||
pkg := b.Func.Pkg
|
||||
sig := fn.raw.Type.(*types.Signature)
|
||||
params := sig.Params()
|
||||
n := params.Len()
|
||||
switch n {
|
||||
case 0:
|
||||
call := pkg.pyFunc("PyObject_CallNoArg", prog.tyCallNoArg())
|
||||
ret = b.Call(call, fn)
|
||||
case 1:
|
||||
call := pkg.pyFunc("PyObject_CallOneArg", prog.tyCallOneArg())
|
||||
ret = b.Call(call, fn, args[0])
|
||||
default:
|
||||
panic("todo")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -25,6 +25,12 @@ import (
|
||||
"github.com/goplus/llvm"
|
||||
)
|
||||
|
||||
func TestSetPython(t *testing.T) {
|
||||
prog := NewProgram(nil)
|
||||
typ := types.NewPackage("foo", "foo")
|
||||
prog.SetPython(typ)
|
||||
}
|
||||
|
||||
func TestClosureCtx(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
@@ -106,10 +112,28 @@ func assertPkg(t *testing.T, p Package, expected string) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPyFunc(t *testing.T) {
|
||||
prog := NewProgram(nil)
|
||||
py := types.NewPackage("foo", "foo")
|
||||
o := types.NewTypeName(0, py, "Object", nil)
|
||||
types.NewNamed(o, types.Typ[types.Int], nil)
|
||||
py.Scope().Insert(o)
|
||||
prog.SetPython(py)
|
||||
pkg := prog.NewPackage("bar", "foo/bar")
|
||||
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
|
||||
a := pkg.NewPyFunc("a", sig)
|
||||
if pkg.NewPyFunc("a", sig) != a {
|
||||
t.Fatal("NewPyFunc(a) failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVar(t *testing.T) {
|
||||
prog := NewProgram(nil)
|
||||
pkg := prog.NewPackage("bar", "foo/bar")
|
||||
a := pkg.NewVar("a", types.Typ[types.Int], InGo)
|
||||
if pkg.NewVar("a", types.Typ[types.Int], InGo) != a {
|
||||
t.Fatal("NewVar(a) failed")
|
||||
}
|
||||
a.Init(prog.Val(100))
|
||||
b := pkg.NewVar("b", types.Typ[types.Int], InGo)
|
||||
b.Init(a.Expr)
|
||||
|
||||
@@ -43,6 +43,7 @@ const (
|
||||
vkFuncDecl
|
||||
vkFuncPtr
|
||||
vkClosure
|
||||
vkPyFunc
|
||||
vkTuple
|
||||
vkPhisExpr = -1
|
||||
)
|
||||
|
||||
@@ -42,6 +42,7 @@ const (
|
||||
inUnknown Background = iota
|
||||
InGo
|
||||
InC
|
||||
InPython
|
||||
)
|
||||
|
||||
// Type convert a Go/C type into raw type.
|
||||
|
||||
Reference in New Issue
Block a user