PyInit
This commit is contained in:
@@ -26,6 +26,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
|
|
||||||
define void @main(i32 %0, ptr %1) {
|
define void @main(i32 %0, ptr %1) {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
|
call void @Py_Initialize()
|
||||||
store i32 %0, ptr @__llgo_argc, align 4
|
store i32 %0, ptr @__llgo_argc, align 4
|
||||||
store ptr %1, ptr @__llgo_argv, align 8
|
store ptr %1, ptr @__llgo_argv, align 8
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
@@ -57,3 +58,5 @@ declare double @PyFloat_AsDouble()
|
|||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
|
|
||||||
declare ptr @PyBytes_AsString()
|
declare ptr @PyBytes_AsString()
|
||||||
|
|
||||||
|
declare void @Py_Initialize()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'math'
|
; ModuleID = 'math'
|
||||||
source_filename = "math"
|
source_filename = "math"
|
||||||
|
|
||||||
@__llgo_py.math.sqrt = external global ptr
|
@__llgo_py.math.sqrt = linkonce global ptr null
|
||||||
@"math.init$guard" = global ptr null
|
@"math.init$guard" = global ptr null
|
||||||
@__llgo_py.math = linkonce global ptr null
|
@__llgo_py.math = linkonce global ptr null
|
||||||
@0 = private unnamed_addr constant [5 x i8] c"math\00", align 1
|
@0 = private unnamed_addr constant [5 x i8] c"math\00", align 1
|
||||||
|
|||||||
@@ -159,6 +159,11 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cl.NewPackage failed:", err)
|
t.Fatal("cl.NewPackage failed:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if prog.NeedPyInit() { // call PyInit if needed
|
||||||
|
ret.PyInit()
|
||||||
|
}
|
||||||
|
|
||||||
if v := ret.String(); v != expected {
|
if v := ret.String(); v != expected {
|
||||||
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -380,8 +380,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func callRuntimeInit(b llssa.Builder, pkg llssa.Package) {
|
func callRuntimeInit(b llssa.Builder, pkg llssa.Package) {
|
||||||
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
|
fn := pkg.NewFunc(RuntimeInit, llssa.NoArgsNoRet, llssa.InC) // don't need to convert runtime.init
|
||||||
fn := pkg.NewFunc(RuntimeInit, sig, llssa.InC) // don't need to convert runtime.init
|
|
||||||
b.Call(fn.Expr)
|
b.Call(fn.Expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func TestFromTestpy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestlibc(t *testing.T) {
|
func TestFromTestlibc(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "./_testlibc", false)
|
cltest.FromDir(t, "", "./_testlibc", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestrt(t *testing.T) {
|
func TestFromTestrt(t *testing.T) {
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ func (p *context) initLink(line string, prefix int, f func(inPkgName string) (fu
|
|||||||
} else {
|
} else {
|
||||||
panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf")
|
panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf")
|
||||||
}
|
}
|
||||||
} else {
|
} else if c := inPkgName[0]; c >= 'A' && c <= 'Z' {
|
||||||
fmt.Fprintln(os.Stderr, "==>", line)
|
fmt.Fprintln(os.Stderr, "==>", line)
|
||||||
fmt.Fprintf(os.Stderr, "llgo: linkname %s not found and ignored\n", inPkgName)
|
fmt.Fprintf(os.Stderr, "llgo: linkname %s not found and ignored\n", inPkgName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,12 +160,22 @@ func Do(args []string, conf *Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNeedRuntime(pkg *packages.Package) {
|
func setNeedRuntimeOrPyInit(pkg *packages.Package, needRuntime, needPyInit bool) {
|
||||||
pkg.ID = "" // just use pkg.Module to mark it needs runtime
|
v := []byte{'0', '0'}
|
||||||
|
if needRuntime {
|
||||||
|
v[0] = '1'
|
||||||
|
}
|
||||||
|
if needPyInit {
|
||||||
|
v[1] = '1'
|
||||||
|
}
|
||||||
|
pkg.ID = string(v) // just use pkg.ID to mark it needs runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNeedRuntime(pkg *packages.Package) bool {
|
func isNeedRuntimeOrPyInit(pkg *packages.Package) (needRuntime, needPyInit bool) {
|
||||||
return pkg.ID == ""
|
if len(pkg.ID) == 2 {
|
||||||
|
return pkg.ID[0] == '1', pkg.ID[1] == '1'
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, verbose bool) (pkgs []*aPackage) {
|
func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, verbose bool) (pkgs []*aPackage) {
|
||||||
@@ -204,9 +214,7 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
|
|||||||
pkg.ExportFile = command
|
pkg.ExportFile = command
|
||||||
default:
|
default:
|
||||||
buildPkg(prog, aPkg, mode, verbose)
|
buildPkg(prog, aPkg, mode, verbose)
|
||||||
if prog.NeedRuntime() {
|
setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime(), prog.NeedPyInit())
|
||||||
setNeedRuntime(pkg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -225,27 +233,43 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, runtimeFiles []string,
|
|||||||
args[1] = app
|
args[1] = app
|
||||||
args[2] = "-Wno-override-module"
|
args[2] = "-Wno-override-module"
|
||||||
needRuntime := false
|
needRuntime := false
|
||||||
|
needPyInit := false
|
||||||
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||||
if p.ExportFile != "" && !isRuntimePkg(p.PkgPath) { // skip packages that only contain declarations
|
if p.ExportFile != "" && !isRuntimePkg(p.PkgPath) { // skip packages that only contain declarations
|
||||||
args = appendLinkFiles(args, p.ExportFile)
|
args = appendLinkFiles(args, p.ExportFile)
|
||||||
|
need1, need2 := isNeedRuntimeOrPyInit(p)
|
||||||
if !needRuntime {
|
if !needRuntime {
|
||||||
needRuntime = isNeedRuntime(p)
|
needRuntime = need1
|
||||||
|
}
|
||||||
|
if !needPyInit {
|
||||||
|
needPyInit = need2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if needRuntime && runtimeFiles != nil {
|
|
||||||
args = append(args, runtimeFiles...)
|
var aPkg *aPackage
|
||||||
} else {
|
for _, v := range pkgs {
|
||||||
for _, aPkg := range pkgs {
|
if v.Package == pkg { // found this package
|
||||||
if aPkg.Package == pkg { // make empty runtime.init if no runtime needed
|
aPkg = v
|
||||||
lpkg := aPkg.LPkg
|
|
||||||
lpkg.FuncOf(cl.RuntimeInit).MakeBody(1).Return()
|
|
||||||
if needLLFile(mode) {
|
|
||||||
os.WriteFile(pkg.ExportFile, []byte(lpkg.String()), 0644)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dirty := false
|
||||||
|
if needRuntime && runtimeFiles != nil {
|
||||||
|
args = append(args, runtimeFiles...)
|
||||||
|
} else {
|
||||||
|
dirty = true
|
||||||
|
fn := aPkg.LPkg.FuncOf(cl.RuntimeInit)
|
||||||
|
fn.MakeBody(1).Return()
|
||||||
|
}
|
||||||
|
if needPyInit {
|
||||||
|
dirty = aPkg.LPkg.PyInit()
|
||||||
|
}
|
||||||
|
|
||||||
|
if dirty && needLLFile(mode) {
|
||||||
|
lpkg := aPkg.LPkg
|
||||||
|
os.WriteFile(pkg.ExportFile, []byte(lpkg.String()), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose || mode != ModeRun {
|
if verbose || mode != ModeRun {
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ func Gen(pkgPath, inFile string, src any) string {
|
|||||||
ret, err := cl.NewPackage(prog, ssaPkg, files)
|
ret, err := cl.NewPackage(prog, ssaPkg, files)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
|
if prog.NeedPyInit() { // call PyInit if needed
|
||||||
|
ret.PyInit()
|
||||||
|
}
|
||||||
|
|
||||||
return ret.String()
|
return ret.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ func GenFrom(fileOrPkg string) string {
|
|||||||
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
|
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
|
if prog.NeedPyInit() { // call PyInit if needed
|
||||||
|
ret.PyInit()
|
||||||
|
}
|
||||||
|
|
||||||
return ret.String()
|
return ret.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFromTestpy(t *testing.T) {
|
func TestFromTestpy(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "../cl/_testpy", false)
|
cltest.FromDir(t, "", "../cl/_testpy", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestrt(t *testing.T) {
|
func TestFromTestrt(t *testing.T) {
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ func (p Package) NewPyFunc(name string, sig *types.Signature) PyFunction {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
prog := p.Prog
|
prog := p.Prog
|
||||||
|
prog.needPyInit = true
|
||||||
obj := p.NewVar(name, prog.PyObjectPtrPtr().RawType(), InC)
|
obj := p.NewVar(name, prog.PyObjectPtrPtr().RawType(), InC)
|
||||||
obj.Init(prog.Null(obj.Type))
|
obj.Init(prog.Null(obj.Type))
|
||||||
obj.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
obj.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
||||||
|
|||||||
@@ -194,6 +194,11 @@ func (p Program) NeedRuntime() bool {
|
|||||||
return p.needRuntime
|
return p.needRuntime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NeedPyInit returns if the current package needs Python initialization.
|
||||||
|
func (p Program) NeedPyInit() bool {
|
||||||
|
return p.needPyInit
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) runtime() *types.Package {
|
func (p Program) runtime() *types.Package {
|
||||||
if p.rt == nil {
|
if p.rt == nil {
|
||||||
p.rt = p.rtget()
|
p.rt = p.rtget()
|
||||||
@@ -262,8 +267,11 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
|||||||
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)
|
pyfns := make(map[string]PyFunction)
|
||||||
|
pymods := make(map[string]Global)
|
||||||
p.needRuntime = false
|
p.needRuntime = false
|
||||||
return &aPackage{mod, gbls, fns, stubs, pyfns, p}
|
// Don't need reset p.needPyInit here
|
||||||
|
// p.needPyInit = false
|
||||||
|
return &aPackage{mod, gbls, fns, stubs, pyfns, pymods, p}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PyObjectPtrPtr returns the **py.Object type.
|
// PyObjectPtrPtr returns the **py.Object type.
|
||||||
@@ -368,6 +376,7 @@ type aPackage struct {
|
|||||||
fns map[string]Function
|
fns map[string]Function
|
||||||
stubs map[string]Function
|
stubs map[string]Function
|
||||||
pyfns map[string]PyFunction
|
pyfns map[string]PyFunction
|
||||||
|
pymods map[string]Global
|
||||||
Prog Program
|
Prog Program
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,23 +515,38 @@ func (p Program) tyCallOneArg() *types.Signature {
|
|||||||
return p.callOneArg
|
return p.callOneArg
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPyMod imports a Python module.
|
// PyInit initializes Python for a main package.
|
||||||
func (b Builder) ImportPyMod(path string) Expr {
|
func (p Package) PyInit() bool {
|
||||||
pkg := b.Func.Pkg
|
if fn := p.FuncOf("main"); fn != nil {
|
||||||
fnImp := pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
|
b := fn.NewBuilder()
|
||||||
return b.Call(fnImp, b.CStr(path))
|
b.SetBlockEx(fn.Block(0), AtStart).CallPyInit()
|
||||||
|
b.Dispose()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
|
if v, ok := p.pymods[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
prog := p.Prog
|
prog := p.Prog
|
||||||
objPtr := prog.PyObjectPtrPtr().raw.Type
|
objPtr := prog.PyObjectPtrPtr().raw.Type
|
||||||
g := p.NewVar(name, objPtr, InC)
|
g := p.NewVar(name, objPtr, InC)
|
||||||
g.Init(prog.Null(g.Type))
|
g.Init(prog.Null(g.Type))
|
||||||
g.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
g.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
||||||
|
p.pymods[name] = g
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
|
|
||||||
func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
|
func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
|
||||||
prog := b.Prog
|
prog := b.Prog
|
||||||
pkg := b.Func.Pkg
|
pkg := b.Func.Pkg
|
||||||
@@ -542,4 +566,14 @@ func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CallPyInit calls Py_Initialize.
|
||||||
|
func (b Builder) CallPyInit() (ret Expr) {
|
||||||
|
fn := b.Func.Pkg.pyFunc("Py_Initialize", NoArgsNoRet)
|
||||||
|
return b.Call(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
NoArgsNoRet = types.NewSignatureType(nil, nil, nil, nil, nil, false)
|
||||||
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -57,15 +57,40 @@ type aBuilder struct {
|
|||||||
// Builder represents a builder for creating instructions in a function.
|
// Builder represents a builder for creating instructions in a function.
|
||||||
type Builder = *aBuilder
|
type Builder = *aBuilder
|
||||||
|
|
||||||
// SetBlock sets the current block to the specified basic block.
|
// Dispose disposes of the builder.
|
||||||
func (b Builder) SetBlock(blk BasicBlock) Builder {
|
func (b Builder) Dispose() {
|
||||||
if b.Func != blk.fn {
|
b.impl.Dispose()
|
||||||
panic("mismatched function")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBlock means SetBlockEx(blk, AtEnd).
|
||||||
|
func (b Builder) SetBlock(blk BasicBlock) Builder {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("Block _llgo_%v:\n", blk.idx)
|
log.Printf("Block _llgo_%v:\n", blk.idx)
|
||||||
}
|
}
|
||||||
|
b.SetBlockEx(blk, AtEnd)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
type InsertPoint int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AtEnd InsertPoint = iota
|
||||||
|
AtStart
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetBlockEx sets blk as current basic block and pos as its insert point.
|
||||||
|
func (b Builder) SetBlockEx(blk BasicBlock, pos InsertPoint) Builder {
|
||||||
|
if b.Func != blk.fn {
|
||||||
|
panic("mismatched function")
|
||||||
|
}
|
||||||
|
switch pos {
|
||||||
|
case AtEnd:
|
||||||
b.impl.SetInsertPointAtEnd(blk.impl)
|
b.impl.SetInsertPointAtEnd(blk.impl)
|
||||||
|
case AtStart:
|
||||||
|
b.impl.SetInsertPointBefore(blk.impl.FirstInstruction())
|
||||||
|
default:
|
||||||
|
panic("SetBlockEx: invalid pos")
|
||||||
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user