diff --git a/_pydemo/matrix/matrix.go b/_pydemo/matrix/matrix.go index 659f8251..ceecb933 100644 --- a/_pydemo/matrix/matrix.go +++ b/_pydemo/matrix/matrix.go @@ -6,24 +6,17 @@ import ( "github.com/goplus/llgo/py/numpy" ) -func matrix(row, col int, vals ...float64) *py.Object { - if len(vals) != row*col { - panic("invalid matrix size") - } - rows := py.NewList(uintptr(row)) - for i := 0; i < row; i++ { - cols := py.NewList(uintptr(col)) - for j := 0; j < col; j++ { - cols.ListSetItem(uintptr(j), py.Float(vals[i*col+j])) - } - rows.ListSetItem(uintptr(i), cols) - } - return numpy.Array(rows, nil) -} - func main() { - a := matrix(3, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9) - b := matrix(3, 3, 9, 8, 7, 6, 5, 4, 3, 2, 1) + a := py.List( + py.List(1.0, 2.0, 3.0), + py.List(4.0, 5.0, 6.0), + py.List(7.0, 8.0, 9.0), + ) + b := py.List( + py.List(9.0, 8.0, 7.0), + py.List(6.0, 5.0, 4.0), + 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()) diff --git a/cl/_testpy/matrix/in.go b/cl/_testpy/matrix/in.go new file mode 100644 index 00000000..ceecb933 --- /dev/null +++ b/cl/_testpy/matrix/in.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/py" + "github.com/goplus/llgo/py/numpy" +) + +func main() { + a := py.List( + py.List(1.0, 2.0, 3.0), + py.List(4.0, 5.0, 6.0), + py.List(7.0, 8.0, 9.0), + ) + b := py.List( + py.List(9.0, 8.0, 7.0), + py.List(6.0, 5.0, 4.0), + 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()) +} diff --git a/cl/_testpy/matrix/out.ll b/cl/_testpy/matrix/out.ll new file mode 100644 index 00000000..e69de29b diff --git a/cl/compile.go b/cl/compile.go index 8d4d92d1..539b80da 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -313,6 +313,8 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj ftype = llgoAllocaCStr case "stringData": ftype = llgoStringData + case "pyList": + ftype = llgoPyList case "unreachable": ftype = llgoUnreachable default: @@ -519,6 +521,14 @@ func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) panic("stringData(s string): invalid arguments") } +func (p *context) pyList(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + vals := make([]llssa.Expr, len(args)) + for i, arg := range args { + vals[i] = p.compileValue(b, arg) + } + return b.PyList(vals...) +} + func isPhi(i ssa.Instruction) bool { _, ok := i.(*ssa.Phi) return ok @@ -615,6 +625,8 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue ret = p.allocaCStr(b, args) case llgoStringData: ret = p.stringData(b, args) + case llgoPyList: + ret = p.pyList(b, args) case llgoUnreachable: // func unreachable() b.Unreachable() default: diff --git a/cl/compile_test.go b/cl/compile_test.go index 6f417cbe..60419bc6 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) { } func TestFromTestpy(t *testing.T) { - cltest.FromDir(t, "", "./_testpy", false) + cltest.FromDir(t, "matrix", "./_testpy", false) } func TestFromTestlibc(t *testing.T) { diff --git a/cl/import.go b/cl/import.go index 11c76ae6..1ab5baea 100644 --- a/cl/import.go +++ b/cl/import.go @@ -318,6 +318,7 @@ const ( llgoAdvance = llgoInstrBase + 4 llgoIndex = llgoInstrBase + 5 llgoStringData = llgoInstrBase + 6 + llgoPyList = llgoInstrBase + 7 ) func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { diff --git a/py/list.go b/py/list.go index 51f6a3de..f87430b0 100644 --- a/py/list.go +++ b/py/list.go @@ -24,6 +24,9 @@ import ( // https://docs.python.org/3/c-api/list.html +//go:linkname List llgo.pyList +func List(args ...any) *Object + // Return a new list of length len on success, or nil on failure. // //go:linkname NewList C.PyList_New diff --git a/ssa/expr.go b/ssa/expr.go index b532984a..7be59134 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -1103,6 +1103,8 @@ func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) { case kind == types.String: return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter} } + case *types.Pointer: + panic("todo: pointer") } panic("todo") } diff --git a/ssa/package.go b/ssa/package.go index 63054a5e..11b68901 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -125,12 +125,12 @@ type aProgram struct { rtSliceTy llvm.Type rtMapTy llvm.Type - anyTy Type - voidTy Type - voidPtr Type - boolTy Type - cstrTy Type - //cintTy Type + anyTy Type + voidTy Type + voidPtr Type + boolTy Type + cstrTy Type + cintTy Type stringTy Type uintptrTy Type intTy Type @@ -138,10 +138,10 @@ type aProgram struct { pyObjPtr Type pyObjPPtr Type - pyImpTy *types.Signature - //pyNewList *types.Signature - //pyListSetI *types.Signature - //callArgs *types.Signature + pyImpTy *types.Signature + pyNewList *types.Signature + pyListSetI *types.Signature + callArgs *types.Signature callNoArgs *types.Signature callOneArg *types.Signature callFOArgs *types.Signature @@ -335,14 +335,12 @@ func (p Program) Any() Type { return p.anyTy } -/* func (p Program) CInt() Type { if p.cintTy == nil { // C.int p.cintTy = p.rawType(types.Typ[types.Int32]) // TODO(xsw): support 64-bit } return p.cintTy } -*/ // Int returns int type. func (p Program) Int() Type { @@ -547,6 +545,7 @@ func (p Program) tyCall() *types.Signature { } return p.callArgs } +*/ func (p Program) tyListSetItem() *types.Signature { if p.pyListSetI == nil { @@ -569,7 +568,17 @@ func (p Program) tyNewList() *types.Signature { } return p.pyNewList } -*/ + +func (p Program) tyFloatFromDouble() *types.Signature { + if p.callArgs == nil { + paramObjPtr := p.paramObjPtr() + paramFloat := types.NewParam(token.NoPos, nil, "", p.Float64().raw.Type) + params := types.NewTuple(paramFloat) + results := types.NewTuple(paramObjPtr) + p.callArgs = types.NewSignatureType(nil, nil, nil, params, results, false) + } + return p.callArgs +} func (p Program) tyLoadPyModSyms() *types.Signature { if p.loadPyModS == nil { @@ -664,7 +673,6 @@ func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) { return } -/* // PyNewList(n uintptr) *Object func (b Builder) PyNewList(n Expr) (ret Expr) { prog := b.Prog @@ -681,18 +689,40 @@ func (b Builder) PyListSetItem(list, index, item Expr) (ret Expr) { return b.Call(fn, list, index, item) } -// PyList(items ...*Object) *Object +// PyList(args ...Expr) *Object func (b Builder) PyList(args ...Expr) (ret Expr) { prog := b.Prog n := len(args) uintPtr := prog.Uintptr() list := b.PyNewList(prog.IntVal(uint64(n), uintPtr)) for i, arg := range args { - b.PyListSetItem(list, prog.IntVal(uint64(i), uintPtr), arg) + b.PyListSetItem(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) { + case *types.Basic: + switch t.Kind() { + case types.Float64: + return b.PyFloat(v) + default: + panic("PyVal: todo") + } + default: + return v + } +} + +// PyFloat(fltVal float64) *Object +func (b Builder) PyFloat(fltVal Expr) (ret Expr) { + prog := b.Prog + pkg := b.Func.Pkg + fn := pkg.pyFunc("PyFloat_FromDouble", prog.tyFloatFromDouble()) + return b.Call(fn, fltVal) +} // CallPyInit calls Py_Initialize. func (b Builder) CallPyInit() (ret Expr) {