diff --git a/README.md b/README.md index 8e2d9c59..0443e077 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,23 @@ llgo - A Go compiler based on LLVM [![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo) [![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop) -This is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem. It's a subproject of [the Go+ project](https://github.com/goplus/gop). +This is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of [the Go+ project](https://github.com/goplus/gop). ## C standard libary support -See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c). +```go +package main + +import "github.com/goplus/llgo/c" + +func main() { + c.Printf(c.Str("Hello world\n")) +} +``` + +This is a simple example of calling the C `printf` function to print `Hello world`. Here, `c.Str` is not a function for converting a Go string to a C string, but a built-in instruction supported by llgo for generating a C string constant. + +See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c) for more detials. ## Python support diff --git a/c/c.go b/c/c.go index fb70ad1a..6db9e572 100644 --- a/c/c.go +++ b/c/c.go @@ -66,7 +66,7 @@ func Memset(s Pointer, c Int, n uintptr) Pointer // ----------------------------------------------------------------------------- -//go:linkname GoStringData github.com/goplus/llgo/internal/runtime.StringData +//go:linkname GoStringData llgo.stringData func GoStringData(string) *Char // ----------------------------------------------------------------------------- diff --git a/cl/_testdata/print/out.ll b/cl/_testdata/print/out.ll index fe4ddeac..af0ea398 100644 --- a/cl/_testdata/print/out.ll +++ b/cl/_testdata/print/out.ll @@ -624,7 +624,7 @@ _llgo_0: _llgo_1: ; preds = %_llgo_3 %2 = urem i64 %14, 16 %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @10, i64 16) - %4 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %3, 0 %5 = getelementptr inbounds i8, ptr %4, i64 %2 %6 = load i8, ptr %5, align 1 %7 = getelementptr inbounds i8, ptr %1, i64 %15 @@ -803,6 +803,4 @@ declare { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"gith declare { %"github.com/goplus/llgo/internal/runtime.String", i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2String"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) -declare ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String") - declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice") diff --git a/cl/_testrt/allocstr/out.ll b/cl/_testrt/allocstr/out.ll index c800e619..5726edc7 100644 --- a/cl/_testrt/allocstr/out.ll +++ b/cl/_testrt/allocstr/out.ll @@ -34,7 +34,7 @@ _llgo_0: call void @"github.com/goplus/llgo/internal/runtime.init"() call void @main.init() %2 = call %"github.com/goplus/llgo/internal/runtime.String" @main.hello() - %3 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %2) + %3 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 1 %4 = add i64 %3, 1 %5 = alloca i8, i64 %4, align 1 %6 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %5, %"github.com/goplus/llgo/internal/runtime.String" %2) @@ -46,8 +46,6 @@ declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/ll declare void @"github.com/goplus/llgo/internal/runtime.init"() -declare i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String") - declare ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr, %"github.com/goplus/llgo/internal/runtime.String") declare i32 @printf(ptr, ...) diff --git a/cl/_testrt/builtin/out.ll b/cl/_testrt/builtin/out.ll index 85393f13..9201f246 100644 --- a/cl/_testrt/builtin/out.ll +++ b/cl/_testrt/builtin/out.ll @@ -131,14 +131,14 @@ _llgo_0: %60 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 5) call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %60) %61 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 5) - %62 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %61) + %62 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %61, 1 %63 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %61, i64 1, i64 %62) call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %63) %64 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 5) %65 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %64, i64 1, i64 2) call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %65) %66 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 5) - %67 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %66) + %67 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %66, 1 %68 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %66, i64 5, i64 %67) call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %68) ret void @@ -152,7 +152,7 @@ _llgo_0: define void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %0) { _llgo_0: - %1 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %0) + %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1 call void @main.out(i64 %1) ret void } @@ -171,8 +171,6 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/go declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) -declare i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String") - declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64) declare i32 @printf(ptr, ...) diff --git a/cl/_testrt/concat/out.ll b/cl/_testrt/concat/out.ll index d343c4e2..e775ef4f 100644 --- a/cl/_testrt/concat/out.ll +++ b/cl/_testrt/concat/out.ll @@ -81,7 +81,7 @@ _llgo_0: %9 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %2, i64 16, i64 3, i64 0, i64 3, i64 3) %10 = call %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %9) %11 = load ptr, ptr @__stderrp, align 8 - %12 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %10) + %12 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %10, 1 %13 = add i64 %12, 1 %14 = alloca i8, i64 %13, align 1 %15 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %14, %"github.com/goplus/llgo/internal/runtime.String" %10) @@ -103,8 +103,6 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) -declare i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String") - declare ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr, %"github.com/goplus/llgo/internal/runtime.String") declare i32 @fprintf(ptr, ptr, ...) diff --git a/cl/_testrt/index/out.ll b/cl/_testrt/index/out.ll index b049b8ae..a9af0027 100644 --- a/cl/_testrt/index/out.ll +++ b/cl/_testrt/index/out.ll @@ -119,12 +119,12 @@ _llgo_0: %61 = load i64, ptr %60, align 4 %62 = call i32 (ptr, ...) @printf(ptr @3, i64 %61) %63 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @5, i64 6) - %64 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %63) + %64 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %63, 0 %65 = getelementptr inbounds i8, ptr %64, i64 2 %66 = load i8, ptr %65, align 1 %67 = call i32 (ptr, ...) @printf(ptr @4, i8 %66) %68 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @7, i64 6) - %69 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %68) + %69 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %68, 0 %70 = getelementptr inbounds i8, ptr %69, i64 1 %71 = load i8, ptr %70, align 1 %72 = call i32 (ptr, ...) @printf(ptr @6, i8 %71) @@ -138,5 +138,3 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr, i64) declare i32 @printf(ptr, ...) declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) - -declare ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String") diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go index 436b272e..3b8c60b2 100644 --- a/cl/cltest/cltest.go +++ b/cl/cltest/cltest.go @@ -160,7 +160,7 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) { t.Fatal("cl.NewPackage failed:", err) } - if prog.NeedPyInit() { // call PyInit if needed + if prog.NeedPyInit { // call PyInit if needed ret.PyInit() } diff --git a/cl/compile.go b/cl/compile.go index a6592e2d..998958ec 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -309,6 +309,8 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyFun ftype = llgoAlloca case "allocaCStr": ftype = llgoAllocaCStr + case "stringData": + ftype = llgoStringData case "unreachable": ftype = llgoUnreachable default: @@ -475,6 +477,15 @@ func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) panic("allocaCStr(s string): invalid arguments") } +// func stringData(s string) *int8 +func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 1 { + s := p.compileValue(b, args[0]) + return b.StringData(s) + } + panic("stringData(s string): invalid arguments") +} + func isPhi(i ssa.Instruction) bool { _, ok := i.(*ssa.Phi) return ok @@ -482,7 +493,7 @@ func isPhi(i ssa.Instruction) bool { func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int { ret := p.fn.Block(block.Index) - b.SetBlock(ret) + b.SetBlockEx(ret, llssa.AtEnd) if ninstr := len(block.Instrs); ninstr > 0 { if isPhi(block.Instrs[0]) { n := 1 @@ -569,6 +580,8 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue ret = p.alloca(b, args) case llgoAllocaCStr: ret = p.allocaCStr(b, args) + case llgoStringData: + ret = p.stringData(b, args) case llgoUnreachable: // func unreachable() b.Unreachable() default: diff --git a/cl/compile_test.go b/cl/compile_test.go index 9430b561..6f417cbe 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -52,6 +52,10 @@ func TestFromTestpymath(t *testing.T) { cltest.Pkg(t, ssa.PkgPython+"/math", "../py/math/llgo_autogen.ll") } +func TestPython(t *testing.T) { + cltest.Pkg(t, ssa.PkgPython, "../py/llgo_autogen.ll") +} + func TestRuntime(t *testing.T) { cltest.Pkg(t, ssa.PkgRuntime, "../internal/runtime/llgo_autogen.ll") } diff --git a/cl/import.go b/cl/import.go index 0afc1c0b..11c76ae6 100644 --- a/cl/import.go +++ b/cl/import.go @@ -317,6 +317,7 @@ const ( llgoAllocaCStr = llgoInstrBase + 3 llgoAdvance = llgoInstrBase + 4 llgoIndex = llgoInstrBase + 5 + llgoStringData = llgoInstrBase + 6 ) func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { diff --git a/internal/build/build.go b/internal/build/build.go index 38ccc5a8..5a834bc7 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -195,26 +195,29 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve // skip packages that only contain declarations // and set no export file pkg.ExportFile = "" - case cl.PkgLinkIR, cl.PkgPyModule: - // skip packages that don't need to be compiled but need to be linked + case cl.PkgLinkIR, cl.PkgLinkExtern, cl.PkgPyModule: pkgPath := pkg.PkgPath if isPkgInLLGo(pkgPath) { pkg.ExportFile = concatPkgLinkFiles(pkgPath) } else { panic("todo") } - case cl.PkgLinkExtern: - // skip packages that don't need to be compiled but need to be linked with external library - linkFile := os.ExpandEnv(strings.TrimSpace(param)) - dir, lib := filepath.Split(linkFile) - command := " -l " + lib - if dir != "" { - command += " -L " + dir + if kind == cl.PkgLinkExtern { // need to be linked with external library + linkFile := os.ExpandEnv(strings.TrimSpace(param)) + dir, lib := filepath.Split(linkFile) + command := " -l " + lib + if dir != "" { + command += " -L " + dir + } + if isMultiLinkFiles(pkg.ExportFile) { + pkg.ExportFile = command + pkg.ExportFile + } else { + pkg.ExportFile = command + " " + pkg.ExportFile + } } - pkg.ExportFile = command default: buildPkg(prog, aPkg, mode, verbose) - setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime(), prog.NeedPyInit()) + setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime, prog.NeedPyInit) } } return diff --git a/internal/llgen/llgen.go b/internal/llgen/llgen.go index 801a81f0..62278f19 100644 --- a/internal/llgen/llgen.go +++ b/internal/llgen/llgen.go @@ -79,7 +79,7 @@ func Gen(pkgPath, inFile string, src any) string { ret, err := cl.NewPackage(prog, ssaPkg, files) check(err) - if prog.NeedPyInit() { // call PyInit if needed + if prog.NeedPyInit { // call PyInit if needed ret.PyInit() } diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 64a06f55..e7f54dce 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -82,7 +82,7 @@ func GenFrom(fileOrPkg string) string { ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax) check(err) - if prog.NeedPyInit() { // call PyInit if needed + if prog.NeedPyInit { // call PyInit if needed ret.PyInit() } diff --git a/internal/pyimport/pyimport.go b/internal/pyimport/pyimport.go deleted file mode 100644 index 72c23de7..00000000 --- a/internal/pyimport/pyimport.go +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package pyimport - -import ( - _ "unsafe" - - "github.com/goplus/llgo/c" - "github.com/goplus/llgo/py" -) - -const ( - LLGoPackage = "decl" -) - -/* -func init() { - py.Initialize() - py.SetProgramName(*c.Argv) -} -*/ - -//go:linkname Module C.PyImport_ImportModule -func Module(name *c.Char) *py.Module diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 9620de0b..452cc462 100644 Binary files a/internal/runtime/llgo_autogen.lla and b/internal/runtime/llgo_autogen.lla differ diff --git a/internal/runtime/z_string.go b/internal/runtime/z_string.go index ee52e2c0..b137447d 100644 --- a/internal/runtime/z_string.go +++ b/internal/runtime/z_string.go @@ -45,16 +45,6 @@ func NewString(data unsafe.Pointer, len int) String { return String{data, len} } -// StringLen returns the length of a string. -func StringLen(s String) int { - return s.len -} - -// StringData returns the data pointer of a string. -func StringData(s String) unsafe.Pointer { - return s.data -} - // StringCat concatenates two strings. func StringCat(a, b String) String { n := a.len + b.len diff --git a/py/_demo/clpy/cleval.go b/py/_demo/clpy/cleval.go index 13f78b80..5b67bc1e 100644 --- a/py/_demo/clpy/cleval.go +++ b/py/_demo/clpy/cleval.go @@ -11,7 +11,7 @@ func main() { code := py.CompileString(c.Str(`print('Hello, World!')`), c.Str(`hello.py`), py.EvalInput) if code != nil { mod := py.ImportModule(c.Str("__main__")) - gbl := mod.GetDict() + gbl := mod.ModuleGetDict() result := py.EvalCode(code, gbl, nil) diff --git a/py/bytes.go b/py/bytes.go index cd6e257a..1b5277db 100644 --- a/py/bytes.go +++ b/py/bytes.go @@ -26,17 +26,17 @@ import ( // String returns a new bytes object from a C string. // -//go:linkname StringFrom C.PyBytes_FromString -func StringFrom(s *c.Char) *Object +//go:linkname FromCStr C.PyBytes_FromString +func FromCStr(s *c.Char) *Object + +// FromString returns a new bytes object from a Go string. +func FromString(s string) *Object { + return stringFromStringAndSize(c.GoStringData(s), uintptr(len(s))) +} //go:linkname stringFromStringAndSize C.PyBytes_FromStringAndSize func stringFromStringAndSize(s *c.Char, size uintptr) *Object -// String returns a new bytes object from a Go string. -func String(s string) *Object { - return stringFromStringAndSize(c.GoStringData(s), uintptr(len(s))) -} - // CStr returns the content of a bytes object as a C string. // // llgo:link (*Object).CStr C.PyBytes_AsString diff --git a/py/llgo_autogen.lla b/py/llgo_autogen.lla new file mode 100644 index 00000000..79b52437 Binary files /dev/null and b/py/llgo_autogen.lla differ diff --git a/py/module.go b/py/module.go index 8dddecbf..59e669c5 100644 --- a/py/module.go +++ b/py/module.go @@ -22,18 +22,13 @@ import ( "github.com/goplus/llgo/c" ) -// Module represents a Python module object. -type Module struct { - Object -} - // ----------------------------------------------------------------------------- // This is a wrapper around py.Import which takes a const char* as an argument // instead of an Object. // //go:linkname ImportModule C.PyImport_ImportModule -func ImportModule(name *c.Char) *Module +func ImportModule(name *c.Char) *Object // This is a higher-level interface that calls the current “import hook function” (with // an explicit level of 0, meaning absolute import). It invokes the __import__() function @@ -43,7 +38,7 @@ func ImportModule(name *c.Char) *Module // This function always uses absolute imports. // //go:linkname Import C.PyImport_Import -func Import(name *Object) *Module +func Import(name *Object) *Object // Return the dictionary object that implements module’s namespace; this object is the same // as the __dict__ attribute of the module object. If module is not a module object (or a @@ -52,7 +47,7 @@ func Import(name *Object) *Module // It is recommended extensions use other Module and Object functions rather than directly // manipulate a module’s __dict__. // -// llgo:link (*Module).GetDict C.PyModule_GetDict -func (m *Module) GetDict() *Object { return nil } +// llgo:link (*Object).ModuleGetDict C.PyModule_GetDict +func (m *Object) ModuleGetDict() *Object { return nil } // ----------------------------------------------------------------------------- diff --git a/py/object.go b/py/object.go index cb973653..6c3d3cc2 100644 --- a/py/object.go +++ b/py/object.go @@ -128,7 +128,7 @@ func (o *Object) CallFunctionObjArgs(__llgo_va_list ...any) *Object { return nil // llgo:link (*Object).CallMethod C.PyObject_CallMethod func (o *Object) CallMethod(name *c.Char, format *c.Char, __llgo_va_list ...any) *Object { - panic("unreachable") + return nil } // llgo:link (*Object).CallMethodObjArgs C.PyObject_CallMethodObjArgs diff --git a/ssa/decl.go b/ssa/decl.go index bc6205ec..f5d1b02c 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -299,7 +299,7 @@ func (p Package) NewPyFunc(name string, sig *types.Signature, doInit bool) PyFun return v } prog := p.Prog - prog.needPyInit = true + prog.NeedPyInit = true obj := p.NewVar(name, prog.PyObjectPtrPtr().RawType(), InC) if doInit { obj.Init(prog.Null(obj.Type)) diff --git a/ssa/expr.go b/ssa/expr.go index 5b4801eb..a97157b8 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -607,6 +607,26 @@ func (b Builder) getField(x Expr, idx int) Expr { return Expr{fld, tfld} } +// StringData returns the data pointer of a string. +func (b Builder) StringData(x Expr) Expr { + if debugInstr { + log.Printf("StringData %v\n", x.impl) + } + prog := b.Prog + ptr := llvm.CreateExtractValue(b.impl, x.impl, 0) + return Expr{ptr, prog.CStr()} +} + +// StringLen returns the length of a string. +func (b Builder) StringLen(x Expr) Expr { + if debugInstr { + log.Printf("StringLen %v\n", x.impl) + } + prog := b.Prog + ptr := llvm.CreateExtractValue(b.impl, x.impl, 1) + return Expr{ptr, prog.Int()} +} + // The IndexAddr instruction yields the address of the element at // index `idx` of collection `x`. `idx` is an integer expression. // @@ -658,8 +678,7 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr { panic(fmt.Errorf("invalid operation: cannot index %v", t)) } telem = prog.rawType(types.Typ[types.Byte]) - pkg := b.Func.Pkg - ptr = b.InlineCall(pkg.rtFunc("StringData"), x) + ptr = b.StringData(x) case *types.Array: telem = prog.Index(x.Type) if addr != nil { @@ -726,7 +745,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) { panic(fmt.Errorf("invalid operation: cannot slice %v", t)) } if high.IsNil() { - high = b.InlineCall(pkg.rtFunc("StringLen"), x) + high = b.StringLen(x) } ret.Type = x.Type ret.impl = b.InlineCall(pkg.rtFunc("NewStringSlice"), x, low, high).impl @@ -880,7 +899,7 @@ func (b Builder) AllocaCStr(gostr Expr) (ret Expr) { log.Printf("AllocaCStr %v\n", gostr.impl) } pkg := b.Func.Pkg - n := b.InlineCall(pkg.rtFunc("StringLen"), gostr) + n := b.StringLen(gostr) n1 := b.BinOp(token.ADD, n, b.Prog.Val(1)) cstr := b.Alloca(n1) return b.InlineCall(pkg.rtFunc("CStrCopy"), cstr, gostr) @@ -1278,7 +1297,7 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { return b.InlineCall(b.Func.Pkg.rtFunc("SliceLen"), arg) case *types.Basic: if t.Kind() == types.String { - return b.InlineCall(b.Func.Pkg.rtFunc("StringLen"), arg) + return b.StringLen(arg) } } } diff --git a/ssa/package.go b/ssa/package.go index cc730c5c..be863bce 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -141,8 +141,8 @@ type aProgram struct { callNoArgs *types.Signature callOneArg *types.Signature - needRuntime bool - needPyInit bool + NeedRuntime bool + NeedPyInit bool } // A Program presents a program. @@ -190,21 +190,11 @@ func (p Program) SetRuntime(runtime any) { } } -// NeedRuntime returns if the current package needs runtime. -func (p Program) NeedRuntime() bool { - 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 { if p.rt == nil { p.rt = p.rtget() } - p.needRuntime = true + p.NeedRuntime = true return p.rt } @@ -269,7 +259,7 @@ func (p Program) NewPackage(name, pkgPath string) Package { stubs := make(map[string]Function) pyfns := make(map[string]PyFunction) pymods := make(map[string]Global) - p.needRuntime = false + p.NeedRuntime = false // Don't need reset p.needPyInit here // p.needPyInit = false return &aPackage{mod, gbls, fns, stubs, pyfns, pymods, p} @@ -398,7 +388,7 @@ func (p Package) rtFunc(fnName string) Expr { } func (p Package) pyFunc(fullName string, sig *types.Signature) Expr { - p.Prog.needPyInit = true + p.Prog.NeedPyInit = true return p.NewFunc(fullName, sig, InC).Expr } diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 2e05b4b5..1afddd0d 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -199,7 +199,7 @@ source_filename = "foo/bar" @a = external global {} `) - if prog.NeedRuntime() { + if prog.NeedRuntime { t.Fatal("NeedRuntime?") } } diff --git a/x/sqlite/llgo_autogen.lla b/x/sqlite/llgo_autogen.lla index e35d151b..cbd7267e 100644 Binary files a/x/sqlite/llgo_autogen.lla and b/x/sqlite/llgo_autogen.lla differ diff --git a/x/sqlite/sqlite.ll b/x/sqlite/sqlite.ll index c0e3dac3..2acb9d94 100644 --- a/x/sqlite/sqlite.ll +++ b/x/sqlite/sqlite.ll @@ -35,8 +35,8 @@ _llgo_0: define { ptr, i32 } @"(*github.com/goplus/llgo/x/sqlite.Sqlite3).Prepare"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1, ptr %2) { _llgo_0: %3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8) - %4 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %1) - %5 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %1) + %4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 0 + %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 1 %6 = trunc i64 %5 to i32 %7 = call i32 @sqlite3_prepare(ptr %0, ptr %4, i32 %6, ptr %3, ptr %2) %8 = load ptr, ptr %3, align 8 @@ -48,8 +48,8 @@ _llgo_0: define { ptr, i32 } @"(*github.com/goplus/llgo/x/sqlite.Sqlite3).PrepareV2"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1, ptr %2) { _llgo_0: %3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8) - %4 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %1) - %5 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %1) + %4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 0 + %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 1 %6 = trunc i64 %5 to i32 %7 = call i32 @sqlite3_prepare_v2(ptr %0, ptr %4, i32 %6, ptr %3, ptr %2) %8 = load ptr, ptr %3, align 8 @@ -61,8 +61,8 @@ _llgo_0: define { ptr, i32 } @"(*github.com/goplus/llgo/x/sqlite.Sqlite3).PrepareV3"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1, i32 %2, ptr %3) { _llgo_0: %4 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8) - %5 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %1) - %6 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %1) + %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 0 + %6 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 1 %7 = trunc i64 %6 to i32 %8 = call i32 @sqlite3_prepare_v3(ptr %0, ptr %5, i32 %7, i32 %2, ptr %4, ptr %3) %9 = load ptr, ptr %4, align 8 @@ -92,10 +92,6 @@ declare i32 @sqlite3_open(ptr, ptr) declare i32 @sqlite3_open_v2(ptr, ptr, i32, ptr) -declare ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String") - -declare i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String") - declare i32 @sqlite3_prepare(ptr, i32, ptr, ptr) declare i32 @sqlite3_prepare_v2(ptr, i32, ptr, ptr)