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) {