From bbeceae42e594f967fda44f9d89fce13e4d63f8e Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 14 Aug 2024 21:39:20 +0800 Subject: [PATCH 1/3] feat(py): Add Python tuple constructor helper --- cl/import.go | 5 +++-- cl/instr.go | 4 ++++ py/tuple.go | 3 +++ ssa/package.go | 2 ++ ssa/python.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/cl/import.go b/cl/import.go index 751414b9..69861dca 100644 --- a/cl/import.go +++ b/cl/import.go @@ -391,8 +391,9 @@ const ( llgoFuncAddr = llgoInstrBase + 0xd - llgoPyList = llgoInstrBase + 0x10 - llgoPyStr = llgoInstrBase + 0x11 + llgoPyList = llgoInstrBase + 0x10 + llgoPyStr = llgoInstrBase + 0x11 + llgoPyTuple = llgoInstrBase + 0x12 llgoAtomicLoad = llgoInstrBase + 0x1d llgoAtomicStore = llgoInstrBase + 0x1e diff --git a/cl/instr.go b/cl/instr.go index 34a764b5..67d0e2c6 100644 --- a/cl/instr.go +++ b/cl/instr.go @@ -216,6 +216,7 @@ var llgoInstrs = map[string]int{ "funcAddr": llgoFuncAddr, "pystr": llgoPyStr, "pyList": llgoPyList, + "pyTuple": llgoPyTuple, "sigjmpbuf": llgoSigjmpbuf, "sigsetjmp": llgoSigsetjmp, "siglongjmp": llgoSiglongjmp, @@ -354,6 +355,9 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon case llgoPyList: args := p.compileValues(b, args, fnHasVArg) ret = b.PyList(args...) + case llgoPyTuple: + args := p.compileValues(b, args, fnHasVArg) + ret = b.PyTuple(args...) case llgoPyStr: ret = pystr(b, args) case llgoCstr: diff --git a/py/tuple.go b/py/tuple.go index 1e15ef0b..d94b00f4 100644 --- a/py/tuple.go +++ b/py/tuple.go @@ -22,6 +22,9 @@ import ( // https://docs.python.org/3/c-api/tuple.html +//go:linkname Tuple llgo.pyTuple +func Tuple(__llgo_va_list ...any) *Object + // Return a new tuple object of size len, or nil on failure. // //go:linkname NewTuple C.PyTuple_New diff --git a/ssa/package.go b/ssa/package.go index d394eb87..ceb10af0 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -169,6 +169,8 @@ type aProgram struct { pyImpTy *types.Signature pyNewList *types.Signature pyListSetI *types.Signature + pyNewTuple *types.Signature + pyTupleSetI *types.Signature floatFromDbl *types.Signature callNoArgs *types.Signature callOneArg *types.Signature diff --git a/ssa/python.go b/ssa/python.go index b0262ddd..d7a526f3 100644 --- a/ssa/python.go +++ b/ssa/python.go @@ -162,6 +162,30 @@ func (p Program) tyNewList() *types.Signature { return p.pyNewList } +// func(*Object, uintptr, *Object) cint +func (p Program) tyTupleSetItem() *types.Signature { + if p.pyTupleSetI == 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.pyTupleSetI = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.pyTupleSetI +} + +// func(uintptr) *Object +func (p Program) tyNewTuple() *types.Signature { + if p.pyNewTuple == nil { + paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type) + params := types.NewTuple(paramUintptr) + results := types.NewTuple(p.paramObjPtr()) + p.pyNewTuple = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.pyNewTuple +} + // func(float64) *Object func (p Program) tyFloatFromDouble() *types.Signature { if p.floatFromDbl == nil { @@ -316,6 +340,32 @@ func (b Builder) PyList(args ...Expr) (ret Expr) { return list } +// PyNewTuple(n int) *Object +func (b Builder) PyNewTuple(n Expr) (ret Expr) { + prog := b.Prog + fn := b.Pkg.pyFunc("PyTuple_New", prog.tyNewTuple()) + return b.Call(fn, n) +} + +// PyListSetItem(list *Object, index uintptr, item *Object) c.Int +func (b Builder) PyTupleSetItem(list, index, item Expr) (ret Expr) { + prog := b.Prog + fn := b.Pkg.pyFunc("PyTuple_SetItem", prog.tyTupleSetItem()) + return b.Call(fn, list, index, item) +} + +// PyList(args ...Expr) *Object +func (b Builder) PyTuple(args ...Expr) (ret Expr) { + prog := b.Prog + n := len(args) + uintPtr := prog.Uintptr() + list := b.PyNewTuple(prog.IntVal(uint64(n), uintPtr)) + for i, arg := range args { + b.PyTupleSetItem(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) { From 6bbe68dfcbf60a44bf32e426e6099ac6a5c22d9c Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 14 Aug 2024 22:07:00 +0800 Subject: [PATCH 2/3] test: Add py.Tuple test --- cl/_testpy/max/in.go | 4 ++++ cl/_testpy/max/out.ll | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cl/_testpy/max/in.go b/cl/_testpy/max/in.go index fcc0bb67..4142c21f 100644 --- a/cl/_testpy/max/in.go +++ b/cl/_testpy/max/in.go @@ -12,4 +12,8 @@ func main() { list := py.List(3.0, 9.0, 23.0, 100.0) y := std.Max(std.Iter(list)) std.Print(y) + + tuple := py.Tuple(1.0, 2.0, 3.0) + z := std.Max(std.Iter(tuple)) + std.Print(z) } diff --git a/cl/_testpy/max/out.ll b/cl/_testpy/max/out.ll index 22a3cfd6..3eae5bed 100644 --- a/cl/_testpy/max/out.ll +++ b/cl/_testpy/max/out.ll @@ -58,6 +58,19 @@ _llgo_0: %22 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %21, ptr %20, ptr null) %23 = load ptr, ptr @__llgo_py.builtins.print, align 8 %24 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %23, ptr %22, ptr null) + %25 = call ptr @PyTuple_New(i64 3) + %26 = call ptr @PyFloat_FromDouble(double 1.000000e+00) + %27 = call i32 @PyTuple_SetItem(ptr %25, i64 0, ptr %26) + %28 = call ptr @PyFloat_FromDouble(double 2.000000e+00) + %29 = call i32 @PyTuple_SetItem(ptr %25, i64 1, ptr %28) + %30 = call ptr @PyFloat_FromDouble(double 3.000000e+00) + %31 = call i32 @PyTuple_SetItem(ptr %25, i64 2, ptr %30) + %32 = load ptr, ptr @__llgo_py.builtins.iter, align 8 + %33 = call ptr @PyObject_CallOneArg(ptr %32, ptr %25) + %34 = load ptr, ptr @__llgo_py.builtins.max, align 8 + %35 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %34, ptr %33, ptr null) + %36 = load ptr, ptr @__llgo_py.builtins.print, align 8 + %37 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %36, ptr %35, ptr null) ret i32 0 } @@ -75,6 +88,10 @@ declare i32 @PyList_SetItem(ptr, i64, ptr) declare ptr @PyObject_CallOneArg(ptr, ptr) +declare ptr @PyTuple_New(i64) + +declare i32 @PyTuple_SetItem(ptr, i64, ptr) + declare void @llgoLoadPyModSyms(ptr, ...) declare void @Py_Initialize() From eb6f487e2a7fd4136e7c2728a51c60c23e88afba Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 14 Aug 2024 22:40:55 +0800 Subject: [PATCH 3/3] fix: typo in document --- ssa/python.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssa/python.go b/ssa/python.go index d7a526f3..d5e49e47 100644 --- a/ssa/python.go +++ b/ssa/python.go @@ -347,14 +347,14 @@ func (b Builder) PyNewTuple(n Expr) (ret Expr) { return b.Call(fn, n) } -// PyListSetItem(list *Object, index uintptr, item *Object) c.Int +// PyTupleSetItem(list *Object, index uintptr, item *Object) c.Int func (b Builder) PyTupleSetItem(list, index, item Expr) (ret Expr) { prog := b.Prog fn := b.Pkg.pyFunc("PyTuple_SetItem", prog.tyTupleSetItem()) return b.Call(fn, list, index, item) } -// PyList(args ...Expr) *Object +// PyTuple(args ...Expr) *Object func (b Builder) PyTuple(args ...Expr) (ret Expr) { prog := b.Prog n := len(args)