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..956009c4 --- /dev/null +++ b/cl/_testpy/matrix/out.ll @@ -0,0 +1,121 @@ +; ModuleID = 'main' +source_filename = "main" + +@"main.init$guard" = global ptr null +@__llgo_argc = global ptr null +@__llgo_argv = global ptr null +@__llgo_py.numpy.add = linkonce global ptr null +@0 = private unnamed_addr constant [8 x i8] c"a = %s\0A\00", align 1 +@1 = private unnamed_addr constant [8 x i8] c"a = %s\0A\00", align 1 +@2 = private unnamed_addr constant [10 x i8] c"a+b = %s\0A\00", align 1 +@__llgo_py.numpy = external global ptr +@3 = private unnamed_addr constant [4 x i8] c"add\00", align 1 + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + call void @"github.com/goplus/llgo/py/numpy.init"() + %1 = load ptr, ptr @__llgo_py.numpy, align 8 + call void (ptr, ...) @llgoLoadPyModSyms(ptr %1, ptr @3, ptr @__llgo_py.numpy.add, ptr null) + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define void @main(i32 %0, ptr %1) { +_llgo_0: + call void @Py_Initialize() + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %2 = call ptr @PyList_New(i64 3) + %3 = call ptr @PyFloat_FromDouble(double 1.000000e+00) + %4 = call i32 @PyList_SetItem(ptr %2, i64 0, ptr %3) + %5 = call ptr @PyFloat_FromDouble(double 2.000000e+00) + %6 = call i32 @PyList_SetItem(ptr %2, i64 1, ptr %5) + %7 = call ptr @PyFloat_FromDouble(double 3.000000e+00) + %8 = call i32 @PyList_SetItem(ptr %2, i64 2, ptr %7) + %9 = call ptr @PyList_New(i64 3) + %10 = call ptr @PyFloat_FromDouble(double 4.000000e+00) + %11 = call i32 @PyList_SetItem(ptr %9, i64 0, ptr %10) + %12 = call ptr @PyFloat_FromDouble(double 5.000000e+00) + %13 = call i32 @PyList_SetItem(ptr %9, i64 1, ptr %12) + %14 = call ptr @PyFloat_FromDouble(double 6.000000e+00) + %15 = call i32 @PyList_SetItem(ptr %9, i64 2, ptr %14) + %16 = call ptr @PyList_New(i64 3) + %17 = call ptr @PyFloat_FromDouble(double 7.000000e+00) + %18 = call i32 @PyList_SetItem(ptr %16, i64 0, ptr %17) + %19 = call ptr @PyFloat_FromDouble(double 8.000000e+00) + %20 = call i32 @PyList_SetItem(ptr %16, i64 1, ptr %19) + %21 = call ptr @PyFloat_FromDouble(double 9.000000e+00) + %22 = call i32 @PyList_SetItem(ptr %16, i64 2, ptr %21) + %23 = call ptr @PyList_New(i64 3) + %24 = call i32 @PyList_SetItem(ptr %23, i64 0, ptr %2) + %25 = call i32 @PyList_SetItem(ptr %23, i64 1, ptr %9) + %26 = call i32 @PyList_SetItem(ptr %23, i64 2, ptr %16) + %27 = call ptr @PyList_New(i64 3) + %28 = call ptr @PyFloat_FromDouble(double 9.000000e+00) + %29 = call i32 @PyList_SetItem(ptr %27, i64 0, ptr %28) + %30 = call ptr @PyFloat_FromDouble(double 8.000000e+00) + %31 = call i32 @PyList_SetItem(ptr %27, i64 1, ptr %30) + %32 = call ptr @PyFloat_FromDouble(double 7.000000e+00) + %33 = call i32 @PyList_SetItem(ptr %27, i64 2, ptr %32) + %34 = call ptr @PyList_New(i64 3) + %35 = call ptr @PyFloat_FromDouble(double 6.000000e+00) + %36 = call i32 @PyList_SetItem(ptr %34, i64 0, ptr %35) + %37 = call ptr @PyFloat_FromDouble(double 5.000000e+00) + %38 = call i32 @PyList_SetItem(ptr %34, i64 1, ptr %37) + %39 = call ptr @PyFloat_FromDouble(double 4.000000e+00) + %40 = call i32 @PyList_SetItem(ptr %34, i64 2, ptr %39) + %41 = call ptr @PyList_New(i64 3) + %42 = call ptr @PyFloat_FromDouble(double 3.000000e+00) + %43 = call i32 @PyList_SetItem(ptr %41, i64 0, ptr %42) + %44 = call ptr @PyFloat_FromDouble(double 2.000000e+00) + %45 = call i32 @PyList_SetItem(ptr %41, i64 1, ptr %44) + %46 = call ptr @PyFloat_FromDouble(double 1.000000e+00) + %47 = call i32 @PyList_SetItem(ptr %41, i64 2, ptr %46) + %48 = call ptr @PyList_New(i64 3) + %49 = call i32 @PyList_SetItem(ptr %48, i64 0, ptr %27) + %50 = call i32 @PyList_SetItem(ptr %48, i64 1, ptr %34) + %51 = call i32 @PyList_SetItem(ptr %48, i64 2, ptr %41) + %52 = load ptr, ptr @__llgo_py.numpy.add, align 8 + %53 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %52, ptr %23, ptr %48, ptr null) + %54 = call ptr @PyObject_Str(ptr %23) + %55 = call ptr @PyUnicode_AsUTF8(ptr %54) + %56 = call i32 (ptr, ...) @printf(ptr @0, ptr %55) + %57 = call ptr @PyObject_Str(ptr %48) + %58 = call ptr @PyUnicode_AsUTF8(ptr %57) + %59 = call i32 (ptr, ...) @printf(ptr @1, ptr %58) + %60 = call ptr @PyObject_Str(ptr %53) + %61 = call ptr @PyUnicode_AsUTF8(ptr %60) + %62 = call i32 (ptr, ...) @printf(ptr @2, ptr %61) + ret void +} + +declare void @"github.com/goplus/llgo/py/numpy.init"() + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare ptr @PyList_New(i64) + +declare ptr @PyFloat_FromDouble(double) + +declare i32 @PyList_SetItem(ptr, i64, ptr) + +declare ptr @PyObject_CallFunctionObjArgs(ptr, ...) + +declare ptr @PyObject_Str(ptr) + +declare ptr @PyUnicode_AsUTF8(ptr) + +declare i32 @printf(ptr, ...) + +declare void @llgoLoadPyModSyms(ptr, ...) + +declare void @Py_Initialize() diff --git a/cl/compile.go b/cl/compile.go index 8d4d92d1..43d88f9f 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: @@ -603,6 +605,9 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue case pyFunc: args := p.compileValues(b, args, kind) ret = b.Call(pyFn.Expr, args...) + case llgoPyList: + args := p.compileValues(b, args, fnHasVArg) + ret = b.PyList(args...) case llgoCstr: ret = cstr(b, args) case llgoAdvance: 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..de52d74d 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(__llgo_va_list ...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/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) {