1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
test.db
|
||||
llgo_autogen.ll
|
||||
stories*.bin
|
||||
.DS_Store
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* 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 main
|
||||
|
||||
import (
|
||||
|
||||
61
_demo/sqlite/sqlite.go
Normal file
61
_demo/sqlite/sqlite.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/x/sqlite"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c.Remove(c.Str("test.db"))
|
||||
|
||||
db, err := sqlite.Open(c.Str("test.db"))
|
||||
check(err, db, "sqlite: Open")
|
||||
|
||||
err = db.Exec(c.Str("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)"), nil, nil, nil)
|
||||
check(err, db, "sqlite: Exec CREATE TABLE")
|
||||
|
||||
stmt, err := db.PrepareV3("INSERT INTO users (id, name) VALUES (?, ?)", 0, nil)
|
||||
check(err, db, "sqlite: PrepareV3 INSERT")
|
||||
|
||||
stmt.BindInt(1, 100)
|
||||
stmt.BindText(2, c.Str("Hello World"), -1, nil)
|
||||
|
||||
err = stmt.Step()
|
||||
checkDone(err, db, "sqlite: Step INSERT 1")
|
||||
|
||||
stmt.Reset()
|
||||
stmt.BindInt(1, 200)
|
||||
stmt.BindText(2, c.Str("This is llgo"), -1, nil)
|
||||
|
||||
err = stmt.Step()
|
||||
checkDone(err, db, "sqlite: Step INSERT 2")
|
||||
|
||||
stmt.Close()
|
||||
|
||||
stmt, err = db.PrepareV3("SELECT * FROM users", 0, nil)
|
||||
check(err, db, "sqlite: PrepareV3 SELECT")
|
||||
|
||||
for {
|
||||
if err = stmt.Step(); err != sqlite.HasRow {
|
||||
break
|
||||
}
|
||||
c.Printf(c.Str("==> id=%d, name=%s\n"), stmt.ColumnInt(0), stmt.ColumnText(1))
|
||||
}
|
||||
checkDone(err, db, "sqlite: Step done")
|
||||
|
||||
stmt.Close()
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func check(err sqlite.Errno, db *sqlite.Sqlite3, at string) {
|
||||
if err != sqlite.OK {
|
||||
c.Printf(c.Str("==> %s Error: (%d) %s\n"), c.AllocaCStr(at), err, db.Errmsg())
|
||||
c.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func checkDone(err sqlite.Errno, db *sqlite.Sqlite3, at string) {
|
||||
if err != sqlite.Done {
|
||||
check(err, db, at)
|
||||
}
|
||||
}
|
||||
12
c/c.go
12
c/c.go
@@ -66,11 +66,21 @@ func Memset(s Pointer, c Int, n uintptr) Pointer
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname GoStringData llgo.stringData
|
||||
//go:linkname GoStringData github.com/goplus/llgo/internal/runtime.StringData
|
||||
func GoStringData(string) *Char
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Remove C.remove
|
||||
func Remove(path *Char) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Exit C.exit
|
||||
func Exit(Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Rand C.rand
|
||||
func Rand() Int
|
||||
|
||||
|
||||
20
cl/_testlibc/sqlite/in.go
Normal file
20
cl/_testlibc/sqlite/in.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/x/sqlite"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := sqlite.OpenV2(c.Str(":memory:"), sqlite.OpenReadWrite|sqlite.OpenMemory, nil)
|
||||
check(err)
|
||||
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func check(err sqlite.Errno) {
|
||||
if err != sqlite.OK {
|
||||
c.Printf(c.Str("==> Error: (%d) %s\n"), err, err.Errstr())
|
||||
c.Exit(1)
|
||||
}
|
||||
}
|
||||
62
cl/_testlibc/sqlite/out.ll
Normal file
62
cl/_testlibc/sqlite/out.ll
Normal file
@@ -0,0 +1,62 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
@"main.init$guard" = global ptr null
|
||||
@0 = private unnamed_addr constant [20 x i8] c"==> Error: (%d) %s\0A\00", align 1
|
||||
@__llgo_argc = global ptr null
|
||||
@__llgo_argv = global ptr null
|
||||
@1 = private unnamed_addr constant [9 x i8] c":memory:\00", align 1
|
||||
|
||||
define void @main.check(i32 %0) {
|
||||
_llgo_0:
|
||||
%1 = icmp ne i32 %0, 0
|
||||
br i1 %1, label %_llgo_1, label %_llgo_2
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
%2 = call ptr @sqlite3_errstr()
|
||||
%3 = call i32 (ptr, ...) @printf(ptr @0, i32 %0, ptr %2)
|
||||
call void @exit(i32 1)
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
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
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @main(i32 %0, ptr %1) {
|
||||
_llgo_0:
|
||||
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, i32 } @"github.com/goplus/llgo/x/sqlite.OpenV2"(ptr @1, i32 130, ptr null)
|
||||
%3 = extractvalue { ptr, i32 } %2, 0
|
||||
%4 = extractvalue { ptr, i32 } %2, 1
|
||||
call void @main.check(i32 %4)
|
||||
%5 = call i32 @sqlite3_close()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare ptr @sqlite3_errstr()
|
||||
|
||||
declare i32 @printf(ptr, ...)
|
||||
|
||||
declare void @exit(i32)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
|
||||
declare { ptr, i32 } @"github.com/goplus/llgo/x/sqlite.OpenV2"(ptr, i32, ptr)
|
||||
|
||||
declare i32 @sqlite3_close()
|
||||
@@ -17,6 +17,7 @@
|
||||
package cl
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/types"
|
||||
"testing"
|
||||
@@ -25,6 +26,27 @@ import (
|
||||
"golang.org/x/tools/go/ssa"
|
||||
)
|
||||
|
||||
func TestRecvTypeName(t *testing.T) {
|
||||
if ret := recvTypeName(&ast.IndexExpr{
|
||||
X: &ast.Ident{Name: "Pointer"},
|
||||
Index: &ast.Ident{Name: "T"},
|
||||
}); ret != "Pointer" {
|
||||
t.Fatal("recvTypeName IndexExpr:", ret)
|
||||
}
|
||||
if ret := recvTypeName(&ast.IndexListExpr{
|
||||
X: &ast.Ident{Name: "Pointer"},
|
||||
Indices: []ast.Expr{&ast.Ident{Name: "T"}},
|
||||
}); ret != "Pointer" {
|
||||
t.Fatal("recvTypeName IndexListExpr:", ret)
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatal("recvTypeName: no error?")
|
||||
}
|
||||
}()
|
||||
recvTypeName(&ast.BadExpr{})
|
||||
}
|
||||
|
||||
/*
|
||||
func TestErrCompileValue(t *testing.T) {
|
||||
defer func() {
|
||||
@@ -160,16 +182,19 @@ func TestErrImport(t *testing.T) {
|
||||
|
||||
func TestErrInitLinkname(t *testing.T) {
|
||||
var ctx context
|
||||
ctx.initLinkname("foo", "//llgo:link abc", func(name string) (bool, bool) {
|
||||
return false, false
|
||||
ctx.initLinkname("//llgo:link abc", func(name string) (string, bool, bool) {
|
||||
return "", false, false
|
||||
})
|
||||
ctx.initLinkname("//go:linkname Printf printf", func(name string) (string, bool, bool) {
|
||||
return "", false, false
|
||||
})
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatal("initLinkname: no error?")
|
||||
}
|
||||
}()
|
||||
ctx.initLinkname("foo", "//go:linkname Printf printf", func(name string) (isVar bool, ok bool) {
|
||||
return false, name == "Printf"
|
||||
ctx.initLinkname("//go:linkname Printf printf", func(name string) (string, bool, bool) {
|
||||
return "foo.Printf", false, name == "Printf"
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ const (
|
||||
PkgLLGo
|
||||
PkgNoInit // noinit: a package that don't need to be initialized
|
||||
PkgDeclOnly // decl: a package that only have declarations
|
||||
PkgLinkOnly // link: a package that don't need to be compiled but need to be linked
|
||||
PkgLinkIR // link llvm ir (.ll)
|
||||
// PkgLinkBitCode // link bitcode (.bc)
|
||||
)
|
||||
|
||||
type pkgInfo struct {
|
||||
|
||||
@@ -40,6 +40,10 @@ func TestFromTestdata(t *testing.T) {
|
||||
cltest.FromDir(t, "", "./_testdata", false)
|
||||
}
|
||||
|
||||
func TestSqlite(t *testing.T) {
|
||||
cltest.Pkg(t, "github.com/goplus/llgo/x/sqlite", "../x/sqlite/sqlite.ll")
|
||||
}
|
||||
|
||||
func TestRuntime(t *testing.T) {
|
||||
cltest.Pkg(t, ssa.PkgRuntime, "../internal/runtime/llgo_autogen.ll")
|
||||
}
|
||||
|
||||
147
cl/import.go
147
cl/import.go
@@ -18,6 +18,7 @@ package cl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
@@ -30,8 +31,9 @@ import (
|
||||
)
|
||||
|
||||
type symInfo struct {
|
||||
file string
|
||||
isVar bool
|
||||
file string
|
||||
fullName string
|
||||
isVar bool
|
||||
}
|
||||
|
||||
type pkgSymInfo struct {
|
||||
@@ -46,7 +48,7 @@ func newPkgSymInfo() *pkgSymInfo {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pkgSymInfo) addSym(fset *token.FileSet, pos token.Pos, name string, isVar bool) {
|
||||
func (p *pkgSymInfo) addSym(fset *token.FileSet, pos token.Pos, fullName, inPkgName string, isVar bool) {
|
||||
f := fset.File(pos)
|
||||
if fp := f.Position(pos); fp.Line > 2 {
|
||||
file := fp.Filename
|
||||
@@ -56,17 +58,17 @@ func (p *pkgSymInfo) addSym(fset *token.FileSet, pos token.Pos, name string, isV
|
||||
p.files[file] = b
|
||||
}
|
||||
}
|
||||
p.syms[name] = symInfo{file, isVar}
|
||||
p.syms[inPkgName] = symInfo{file, fullName, isVar}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pkgSymInfo) initLinknames(ctx *context, pkgPath string) {
|
||||
func (p *pkgSymInfo) initLinknames(ctx *context) {
|
||||
for file, b := range p.files {
|
||||
lines := bytes.Split(b, []byte{'\n'})
|
||||
for _, line := range lines {
|
||||
ctx.initLinkname(pkgPath, string(line), func(name string) (isVar bool, ok bool) {
|
||||
if sym, ok := p.syms[name]; ok && file == sym.file {
|
||||
return sym.isVar, true
|
||||
ctx.initLinkname(string(line), func(inPkgName string) (fullName string, isVar, ok bool) {
|
||||
if sym, ok := p.syms[inPkgName]; ok && file == sym.file {
|
||||
return sym.fullName, sym.isVar, true
|
||||
}
|
||||
return
|
||||
})
|
||||
@@ -89,7 +91,9 @@ func PkgKindOf(pkg *types.Package) int {
|
||||
func pkgKind(v string) int {
|
||||
switch v {
|
||||
case "link":
|
||||
return PkgLinkOnly
|
||||
return PkgLinkIR
|
||||
// case "link:bc":
|
||||
// return PkgLinkBitCode
|
||||
case "decl":
|
||||
return PkgDeclOnly
|
||||
case "noinit":
|
||||
@@ -116,24 +120,34 @@ func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
|
||||
}
|
||||
i.kind = kind
|
||||
fset := p.fset
|
||||
pkgPath := llssa.PathOf(pkg)
|
||||
names := scope.Names()
|
||||
syms := newPkgSymInfo()
|
||||
for _, name := range names {
|
||||
if token.IsExported(name) {
|
||||
obj := scope.Lookup(name)
|
||||
switch obj := obj.(type) {
|
||||
case *types.Func:
|
||||
if pos := obj.Pos(); pos != token.NoPos {
|
||||
syms.addSym(fset, pos, name, false)
|
||||
}
|
||||
case *types.Var:
|
||||
if pos := obj.Pos(); pos != token.NoPos {
|
||||
syms.addSym(fset, pos, name, true)
|
||||
obj := scope.Lookup(name)
|
||||
switch obj := obj.(type) {
|
||||
case *types.Func:
|
||||
if pos := obj.Pos(); pos != token.NoPos {
|
||||
fullName, inPkgName := typesFuncName(pkgPath, obj)
|
||||
syms.addSym(fset, pos, fullName, inPkgName, false)
|
||||
}
|
||||
case *types.TypeName:
|
||||
if !obj.IsAlias() {
|
||||
if t, ok := obj.Type().(*types.Named); ok {
|
||||
for i, n := 0, t.NumMethods(); i < n; i++ {
|
||||
fn := t.Method(i)
|
||||
fullName, inPkgName := typesFuncName(pkgPath, fn)
|
||||
syms.addSym(fset, fn.Pos(), fullName, inPkgName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
case *types.Var:
|
||||
if pos := obj.Pos(); pos != token.NoPos {
|
||||
syms.addSym(fset, pos, pkgPath+"."+name, name, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
syms.initLinknames(p, llssa.PathOf(pkg))
|
||||
syms.initLinknames(p)
|
||||
}
|
||||
|
||||
func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
||||
@@ -141,13 +155,13 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
||||
for _, decl := range file.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if decl.Recv == nil {
|
||||
p.initLinknameByDoc(decl.Doc, pkgPath, decl.Name.Name, false)
|
||||
}
|
||||
fullName, inPkgName := astFuncName(pkgPath, decl)
|
||||
p.initLinknameByDoc(decl.Doc, fullName, inPkgName, false)
|
||||
case *ast.GenDecl:
|
||||
if decl.Tok == token.VAR && len(decl.Specs) == 1 {
|
||||
if names := decl.Specs[0].(*ast.ValueSpec).Names; len(names) == 1 {
|
||||
p.initLinknameByDoc(decl.Doc, pkgPath, names[0].Name, true)
|
||||
inPkgName := names[0].Name
|
||||
p.initLinknameByDoc(decl.Doc, pkgPath+"."+inPkgName, inPkgName, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,50 +169,107 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *context) initLinknameByDoc(doc *ast.CommentGroup, pkgPath, expName string, isVar bool) {
|
||||
func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar bool) {
|
||||
if doc != nil {
|
||||
if n := len(doc.List); n > 0 {
|
||||
line := doc.List[n-1].Text
|
||||
p.initLinkname(pkgPath, line, func(name string) (bool, bool) {
|
||||
return isVar, name == expName
|
||||
p.initLinkname(line, func(name string) (_ string, _, ok bool) {
|
||||
return fullName, isVar, name == inPkgName
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *context) initLinkname(pkgPath, line string, f func(name string) (isVar bool, ok bool)) {
|
||||
func (p *context) initLinkname(line string, f func(inPkgName string) (fullName string, isVar, ok bool)) {
|
||||
const (
|
||||
linkname = "//go:linkname "
|
||||
llgolink = "//llgo:link "
|
||||
llgolink2 = "// llgo:link "
|
||||
)
|
||||
if strings.HasPrefix(line, linkname) {
|
||||
p.initLink(pkgPath, line, len(linkname), f)
|
||||
p.initLink(line, len(linkname), f)
|
||||
} else if strings.HasPrefix(line, llgolink2) {
|
||||
p.initLink(pkgPath, line, len(llgolink2), f)
|
||||
p.initLink(line, len(llgolink2), f)
|
||||
} else if strings.HasPrefix(line, llgolink) {
|
||||
p.initLink(pkgPath, line, len(llgolink), f)
|
||||
p.initLink(line, len(llgolink), f)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *context) initLink(pkgPath string, line string, prefix int, f func(name string) (isVar bool, ok bool)) {
|
||||
func (p *context) initLink(line string, prefix int, f func(inPkgName string) (fullName string, isVar, ok bool)) {
|
||||
text := strings.TrimSpace(line[prefix:])
|
||||
if idx := strings.IndexByte(text, ' '); idx > 0 {
|
||||
name := text[:idx]
|
||||
if isVar, ok := f(name); ok {
|
||||
inPkgName := text[:idx]
|
||||
if fullName, isVar, ok := f(inPkgName); ok {
|
||||
link := strings.TrimLeft(text[idx+1:], " ")
|
||||
if isVar || strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr
|
||||
name := pkgPath + "." + name
|
||||
p.link[name] = link
|
||||
p.link[fullName] = link
|
||||
} else {
|
||||
panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf")
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, "==>", line)
|
||||
fmt.Fprintf(os.Stderr, "llgo: linkname %s not found and ignored\n", inPkgName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func: pkg.name
|
||||
// method: (pkg.T).name, (*pkg.T).name
|
||||
func recvTypeName(t ast.Expr) string {
|
||||
switch t := t.(type) {
|
||||
case *ast.Ident:
|
||||
return t.Name
|
||||
case *ast.IndexExpr:
|
||||
return trecvTypeName(t.X, t.Index)
|
||||
case *ast.IndexListExpr:
|
||||
return trecvTypeName(t.X, t.Indices...)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// TODO(xsw): support generic type
|
||||
func trecvTypeName(t ast.Expr, indices ...ast.Expr) string {
|
||||
_ = indices
|
||||
return t.(*ast.Ident).Name
|
||||
}
|
||||
|
||||
// inPkgName:
|
||||
// - func: name
|
||||
// - method: (T).name, (*T).name
|
||||
// fullName:
|
||||
// - func: pkg.name
|
||||
// - method: (pkg.T).name, (*pkg.T).name
|
||||
func astFuncName(pkgPath string, fn *ast.FuncDecl) (fullName, inPkgName string) {
|
||||
name := fn.Name.Name
|
||||
if recv := fn.Recv; recv != nil && len(recv.List) == 1 {
|
||||
tPrefix := "("
|
||||
t := recv.List[0].Type
|
||||
if tp, ok := t.(*ast.StarExpr); ok {
|
||||
t, tPrefix = tp.X, "(*"
|
||||
}
|
||||
tSuffix := recvTypeName(t) + ")." + name
|
||||
return tPrefix + pkgPath + "." + tSuffix, tPrefix + tSuffix
|
||||
}
|
||||
return pkgPath + "." + name, name
|
||||
}
|
||||
|
||||
func typesFuncName(pkgPath string, fn *types.Func) (fullName, inPkgName string) {
|
||||
sig := fn.Type().(*types.Signature)
|
||||
name := fn.Name()
|
||||
if recv := sig.Recv(); recv != nil {
|
||||
tPrefix := "("
|
||||
t := recv.Type()
|
||||
if tp, ok := t.(*types.Pointer); ok {
|
||||
t, tPrefix = tp.Elem(), "(*"
|
||||
}
|
||||
tSuffix := t.(*types.Named).Obj().Name() + ")." + name
|
||||
return tPrefix + pkgPath + "." + tSuffix, tPrefix + tSuffix
|
||||
}
|
||||
return pkgPath + "." + name, name
|
||||
}
|
||||
|
||||
// TODO(xsw): may can use typesFuncName
|
||||
// fullName:
|
||||
// - func: pkg.name
|
||||
// - method: (pkg.T).name, (*pkg.T).name
|
||||
func funcName(pkg *types.Package, fn *ssa.Function) string {
|
||||
sig := fn.Signature
|
||||
name := fn.Name()
|
||||
|
||||
@@ -167,16 +167,16 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
|
||||
}
|
||||
for _, aPkg := range pkgs {
|
||||
pkg := aPkg.Package
|
||||
switch cl.PkgKindOf(pkg.Types) {
|
||||
switch kind := cl.PkgKindOf(pkg.Types); kind {
|
||||
case cl.PkgDeclOnly:
|
||||
// skip packages that only contain declarations
|
||||
// and set no export file
|
||||
pkg.ExportFile = ""
|
||||
case cl.PkgLinkOnly:
|
||||
case cl.PkgLinkIR: // cl.PkgLinkBitCode:
|
||||
// skip packages that don't need to be compiled but need to be linked
|
||||
pkgPath := pkg.PkgPath
|
||||
if isPkgInLLGo(pkgPath) {
|
||||
pkg.ExportFile = strings.TrimSuffix(llgoPkgLinkFile(pkgPath), ".ll")
|
||||
pkg.ExportFile = concatPkgLinkFiles(pkgPath)
|
||||
} else {
|
||||
panic("todo")
|
||||
}
|
||||
@@ -205,7 +205,7 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, runtimeFiles []string,
|
||||
needRuntime := false
|
||||
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||
if p.ExportFile != "" && !isRuntimePkg(p.PkgPath) { // skip packages that only contain declarations
|
||||
args = append(args, p.ExportFile+".ll")
|
||||
args = appendLinkFiles(args, p.ExportFile)
|
||||
if !needRuntime {
|
||||
needRuntime = isNeedRuntime(p)
|
||||
}
|
||||
@@ -219,8 +219,7 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, runtimeFiles []string,
|
||||
lpkg := aPkg.LPkg
|
||||
lpkg.FuncOf(cl.RuntimeInit).MakeBody(1).Return()
|
||||
if needLLFile(mode) {
|
||||
file := pkg.ExportFile + ".ll"
|
||||
os.WriteFile(file, []byte(lpkg.String()), 0644)
|
||||
os.WriteFile(pkg.ExportFile, []byte(lpkg.String()), 0644)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -265,8 +264,8 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) {
|
||||
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)
|
||||
check(err)
|
||||
if needLLFile(mode) {
|
||||
file := pkg.ExportFile + ".ll"
|
||||
os.WriteFile(file, []byte(ret.String()), 0644)
|
||||
pkg.ExportFile += ".ll"
|
||||
os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644)
|
||||
}
|
||||
aPkg.LPkg = ret
|
||||
}
|
||||
@@ -358,8 +357,9 @@ func allLinkFiles(rt []*packages.Package) (outFiles []string) {
|
||||
packages.Visit(rt, nil, func(p *packages.Package) {
|
||||
pkgPath := p.PkgPath
|
||||
if isRuntimePkg(pkgPath) {
|
||||
outFile := llgoPkgLinkFile(pkgPath)
|
||||
outFiles = append(outFiles, outFile)
|
||||
llgoPkgLinkFiles(pkgPath, func(linkFile string) {
|
||||
outFiles = append(outFiles, linkFile)
|
||||
})
|
||||
}
|
||||
})
|
||||
return
|
||||
@@ -393,12 +393,57 @@ func llgoRoot() string {
|
||||
return rootDir
|
||||
}
|
||||
|
||||
func llgoPkgLinkFile(pkgPath string) string {
|
||||
llFile := filepath.Join(llgoRoot()+pkgPath[len(llgoModPath):], "llgo_autogen.ll")
|
||||
if _, err := os.Stat(llFile); os.IsNotExist(err) {
|
||||
decodeLinkFile(llFile)
|
||||
func appendLinkFiles(args []string, file string) []string {
|
||||
if isMultiLinkFiles(file) {
|
||||
return append(args, strings.Split(file[1:], " ")...)
|
||||
}
|
||||
return append(args, file)
|
||||
}
|
||||
|
||||
func isMultiLinkFiles(ret string) bool {
|
||||
return len(ret) > 0 && ret[0] == ' '
|
||||
}
|
||||
|
||||
func concatPkgLinkFiles(pkgPath string) string {
|
||||
var b strings.Builder
|
||||
var ret string
|
||||
var n int
|
||||
llgoPkgLinkFiles(pkgPath, func(linkFile string) {
|
||||
if n == 0 {
|
||||
ret = linkFile
|
||||
} else {
|
||||
b.WriteByte(' ')
|
||||
b.WriteString(linkFile)
|
||||
}
|
||||
n++
|
||||
})
|
||||
if n > 1 {
|
||||
b.WriteByte(' ')
|
||||
b.WriteString(ret)
|
||||
return b.String()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func llgoPkgLinkFiles(pkgPath string, procFile func(linkFile string)) {
|
||||
dir := llgoRoot() + pkgPath[len(llgoModPath):] + "/"
|
||||
llFile := dir + "llgo_autogen.ll"
|
||||
llaFile := llFile + "a"
|
||||
zipf, err := zip.OpenReader(llaFile)
|
||||
if err != nil {
|
||||
procFile(llFile)
|
||||
return
|
||||
}
|
||||
defer zipf.Close()
|
||||
|
||||
for _, f := range zipf.File {
|
||||
procFile(dir + f.Name)
|
||||
}
|
||||
if _, err := os.Stat(llFile); os.IsNotExist(err) {
|
||||
for _, f := range zipf.File {
|
||||
decodeFile(dir+f.Name, f)
|
||||
}
|
||||
}
|
||||
return llFile
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -417,6 +462,18 @@ func isPkgInMod(pkgPath, modPath string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
func llgoPkgLinkFile(pkgPath string) string {
|
||||
// if kind == cl.PkgLinkBitCode {
|
||||
// return filepath.Join(llgoRoot()+pkgPath[len(llgoModPath):], "llgo_autogen.bc")
|
||||
// }
|
||||
llFile := filepath.Join(llgoRoot()+pkgPath[len(llgoModPath):], "llgo_autogen.ll")
|
||||
if _, err := os.Stat(llFile); os.IsNotExist(err) {
|
||||
decodeLinkFile(llFile)
|
||||
}
|
||||
return llFile
|
||||
}
|
||||
|
||||
// *.ll => *.lla
|
||||
func decodeLinkFile(llFile string) {
|
||||
zipFile := llFile + "a"
|
||||
@@ -435,6 +492,20 @@ func decodeLinkFile(llFile string) {
|
||||
os.WriteFile(llFile, data, 0644)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func decodeFile(outFile string, zipf *zip.File) (err error) {
|
||||
f, err := zipf.Open()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
data, err := io.ReadAll(f)
|
||||
if err == nil {
|
||||
err = os.WriteFile(outFile, data, 0644)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ package llgen
|
||||
import (
|
||||
"go/types"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -74,10 +75,15 @@ func DoFile(fileOrPkg, outFile string) {
|
||||
}
|
||||
|
||||
func SmartDoFile(inFile string, pkgPath ...string) {
|
||||
const autgenFile = "llgo_autogen.ll"
|
||||
dir, _ := filepath.Split(inFile)
|
||||
fname := "llgo_autogen.ll"
|
||||
if inCompilerDir(dir) {
|
||||
absDir, _ := filepath.Abs(dir)
|
||||
absDir = filepath.ToSlash(absDir)
|
||||
fname := autgenFile
|
||||
if inCompilerDir(absDir) {
|
||||
fname = "out.ll"
|
||||
} else if inSqlite(absDir) {
|
||||
fname = "sqlite.ll"
|
||||
}
|
||||
outFile := dir + fname
|
||||
|
||||
@@ -86,9 +92,23 @@ func SmartDoFile(inFile string, pkgPath ...string) {
|
||||
} else {
|
||||
DoFile(inFile, outFile)
|
||||
}
|
||||
if false && fname == autgenFile {
|
||||
genZip(absDir, "llgo_autogen.lla", autgenFile)
|
||||
}
|
||||
}
|
||||
|
||||
func genZip(dir string, outFile, inFile string) {
|
||||
cmd := exec.Command("zip", outFile, inFile)
|
||||
cmd.Dir = dir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Run()
|
||||
}
|
||||
|
||||
func inCompilerDir(dir string) bool {
|
||||
dir, _ = filepath.Abs(dir)
|
||||
return strings.Contains(filepath.ToSlash(dir), "/llgo/cl/")
|
||||
return strings.Contains(dir, "/llgo/cl/")
|
||||
}
|
||||
|
||||
func inSqlite(dir string) bool {
|
||||
return strings.HasSuffix(dir, "/llgo/x/sqlite")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
* 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.
|
||||
@@ -14,12 +14,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package gocmd
|
||||
package llvmlink
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type BuildConfig struct {
|
||||
Output string
|
||||
// Cmd represents a llvm-link command.
|
||||
type Cmd struct {
|
||||
app string
|
||||
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
}
|
||||
|
||||
// New creates a new llvm-link command.
|
||||
func New(app string) *Cmd {
|
||||
if app == "" {
|
||||
app = os.Getenv("LLGO_LLVM_ROOT") + "/bin/llvm-link"
|
||||
}
|
||||
return &Cmd{app, os.Stdout, os.Stderr}
|
||||
}
|
||||
|
||||
func (p *Cmd) Exec(args ...string) error {
|
||||
cmd := exec.Command(p.app, args...)
|
||||
cmd.Stdout = p.Stdout
|
||||
cmd.Stderr = p.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -5,6 +5,6 @@
|
||||
"../sqlite/configure",
|
||||
"make",
|
||||
"clang -emit-llvm -S -o ../llgo_autogen.ll -c sqlite3.c",
|
||||
"zip ../llgo_autogen.lla ../llgo_autogen.ll"
|
||||
"cd ..; rm llgo_autogen.lla; zip llgo_autogen.lla llgo_autogen.ll sqlite.ll",
|
||||
]
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -29,49 +29,9 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "noinit,link"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Errno Int
|
||||
|
||||
const (
|
||||
OK Errno = 0 // Successful result
|
||||
Error Errno = 1 // Generic error
|
||||
ErrInternal Errno = 2 // Internal logic error in SQLite
|
||||
ErrPerm Errno = 3 // Access permission denied
|
||||
ErrAbort Errno = 4 // Callback routine requested an abort
|
||||
ErrBusy Errno = 5 // The database file is locked
|
||||
ErrLocked Errno = 6 // A table in the database is locked
|
||||
ErrNomem Errno = 7 // A malloc() failed
|
||||
ErrReadOnly Errno = 8 // Attempt to write a readonly database
|
||||
ErrInterrupt Errno = 9 // Operation terminated by sqlite3_interrupt()
|
||||
ErrIo Errno = 10 // Some kind of disk I/O error occurred
|
||||
ErrCorrupt Errno = 11 // The database disk image is malformed
|
||||
ErrNotfound Errno = 12 // Unknown opcode in sqlite3_file_control()
|
||||
ErrFull Errno = 13 // Insertion failed because database is full
|
||||
ErrCantopen Errno = 14 // Unable to open the database file
|
||||
ErrProtocol Errno = 15 // Database lock protocol error
|
||||
_ErrEmpty Errno = 16 // Internal use only
|
||||
ErrSchema Errno = 17 // The database schema changed
|
||||
ErrToobig Errno = 18 // String or BLOB exceeds size limit
|
||||
ErrConstraint Errno = 19 // Abort due to constraint violation
|
||||
ErrMismatch Errno = 20 // Data type mismatch
|
||||
ErrMisuse Errno = 21 // Library used incorrectly
|
||||
ErrNolfs Errno = 22 // Uses OS features not supported on host
|
||||
ErrAuth Errno = 23 // Authorization denied
|
||||
_ErrFormat Errno = 24 // Not used
|
||||
ErrRange Errno = 25 // 2nd parameter to sqlite3_bind out of range
|
||||
ErrNotadb Errno = 26 // File opened that is not a database file
|
||||
ErrNotice Errno = 27 // Notifications from sqlite3_log()
|
||||
ErrWarning Errno = 28 // Warnings from sqlite3_log()
|
||||
ErrRow Errno = 100 // sqlite3_step() has another row ready
|
||||
ErrDone Errno = 101 // sqlite3_step() has finished executing
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// llgo:type C
|
||||
type Sqlite3 struct {
|
||||
}
|
||||
@@ -82,6 +42,58 @@ type Stmt struct {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Errno Int
|
||||
|
||||
const (
|
||||
OK Errno = 0 // Successful result
|
||||
|
||||
Error Errno = 1 // Generic error
|
||||
ErrInternal Errno = 2 // Internal logic error in SQLite
|
||||
ErrPerm Errno = 3 // Access permission denied
|
||||
ErrAbort Errno = 4 // Callback routine requested an abort
|
||||
ErrBusy Errno = 5 // The database file is locked
|
||||
ErrLocked Errno = 6 // A table in the database is locked
|
||||
ErrNomem Errno = 7 // A malloc() failed
|
||||
ErrReadOnly Errno = 8 // Attempt to write a readonly database
|
||||
ErrInterrupt Errno = 9 // Operation terminated by sqlite3_interrupt()
|
||||
ErrIo Errno = 10 // Some kind of disk I/O error occurred
|
||||
ErrCorrupt Errno = 11 // The database disk image is malformed
|
||||
ErrNotfound Errno = 12 // Unknown opcode in sqlite3_file_control()
|
||||
ErrFull Errno = 13 // Insertion failed because database is full
|
||||
ErrCantopen Errno = 14 // Unable to open the database file
|
||||
ErrProtocol Errno = 15 // Database lock protocol error
|
||||
_ErrEmpty Errno = 16 // Internal use only
|
||||
ErrSchema Errno = 17 // The database schema changed
|
||||
ErrToobig Errno = 18 // String or BLOB exceeds size limit
|
||||
ErrConstraint Errno = 19 // Abort due to constraint violation
|
||||
ErrMismatch Errno = 20 // Data type mismatch
|
||||
ErrMisuse Errno = 21 // Library used incorrectly
|
||||
ErrNolfs Errno = 22 // Uses OS features not supported on host
|
||||
ErrAuth Errno = 23 // Authorization denied
|
||||
_ErrFormat Errno = 24 // Not used
|
||||
ErrRange Errno = 25 // 2nd parameter to sqlite3_bind out of range
|
||||
ErrNotadb Errno = 26 // File opened that is not a database file
|
||||
ErrNotice Errno = 27 // Notifications from sqlite3_log()
|
||||
ErrWarning Errno = 28 // Warnings from sqlite3_log()
|
||||
|
||||
HasRow Errno = 100 // sqlite3_step() has another row ready
|
||||
Done Errno = 101 // sqlite3_step() has finished executing
|
||||
)
|
||||
|
||||
// llgo:link (Errno).Errstr C.sqlite3_errstr
|
||||
func (err Errno) Errstr() *Char { return nil }
|
||||
|
||||
// llgo:link (*Sqlite3).Errmsg C.sqlite3_errmsg
|
||||
func (db *Sqlite3) Errmsg() *Char { return nil }
|
||||
|
||||
// llgo:link (*Sqlite3).Errcode C.sqlite3_errcode
|
||||
func (db *Sqlite3) Errcode() Errno { return 0 }
|
||||
|
||||
// llgo:link (*Sqlite3).ExtendedErrcode C.sqlite3_extended_errcode
|
||||
func (db *Sqlite3) ExtendedErrcode() Errno { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname doOpen C.sqlite3_open
|
||||
func doOpen(filename *Char, ppDb **Sqlite3) Errno
|
||||
|
||||
@@ -134,12 +146,12 @@ func OpenV2(filename *Char, flags OpenFlags, zVfs *Char) (db *Sqlite3, err Errno
|
||||
// Closing A Database Connection
|
||||
//
|
||||
// llgo:link (*Sqlite3).Close C.sqlite3_close
|
||||
func (*Sqlite3) Close() Errno { return 0 }
|
||||
func (db *Sqlite3) Close() Errno { return 0 }
|
||||
|
||||
// Closing A Database Connection
|
||||
//
|
||||
// llgo:link (*Sqlite3).CloseV2 C.sqlite3_close_v2
|
||||
func (*Sqlite3) CloseV2() Errno { return 0 }
|
||||
func (db *Sqlite3) CloseV2() Errno { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -168,22 +180,27 @@ const (
|
||||
)
|
||||
|
||||
// Compiling An SQL Statement
|
||||
// tail: Pointer to unused portion of zSql
|
||||
func (db *Sqlite3) Prepare(sql string) (stmt *Stmt, tail *Char, err Errno) {
|
||||
err = db.doPrepare(c.GoStringData(sql), c.Int(len(sql)), &stmt, &tail)
|
||||
// tail: Pointer to unused portion of sql
|
||||
func (db *Sqlite3) Prepare(sql string, tail **Char) (stmt *Stmt, err Errno) {
|
||||
err = db.doPrepare(c.GoStringData(sql), c.Int(len(sql)), &stmt, tail)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Sqlite3) PrepareV2(sql string) (stmt *Stmt, tail *Char, err Errno) {
|
||||
err = db.doPrepareV2(c.GoStringData(sql), c.Int(len(sql)), &stmt, &tail)
|
||||
func (db *Sqlite3) PrepareV2(sql string, tail **Char) (stmt *Stmt, err Errno) {
|
||||
err = db.doPrepareV2(c.GoStringData(sql), c.Int(len(sql)), &stmt, tail)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Sqlite3) PrepareV3(sql string, flags PrepareFlags) (stmt *Stmt, tail *Char, err Errno) {
|
||||
err = db.doPrepareV3(c.GoStringData(sql), c.Int(len(sql)), flags, &stmt, &tail)
|
||||
func (db *Sqlite3) PrepareV3(sql string, flags PrepareFlags, tail **Char) (stmt *Stmt, err Errno) {
|
||||
err = db.doPrepareV3(c.GoStringData(sql), c.Int(len(sql)), flags, &stmt, tail)
|
||||
return
|
||||
}
|
||||
|
||||
// Destroy A Prepared Statement Object
|
||||
//
|
||||
// llgo:link (*Stmt).Close C.sqlite3_finalize
|
||||
func (stmt *Stmt) Close() Errno { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// llgo:link (*Stmt).BindInt C.sqlite3_bind_int
|
||||
@@ -192,15 +209,25 @@ func (*Stmt) BindInt(idx Int, val Int) Errno { return 0 }
|
||||
// llgo:link (*Stmt).BindInt64 C.sqlite3_bind_int64
|
||||
func (*Stmt) BindInt64(idx Int, val int64) Errno { return 0 }
|
||||
|
||||
// llgo:link (*Stmt).doBindText C.sqlite3_bind_text
|
||||
func (*Stmt) doBindText(Int, *Char, Int, func(Pointer)) Errno { return 0 }
|
||||
/*
|
||||
const (
|
||||
Static = (func(Pointer))(nil) // val is a static string
|
||||
Transient = (func(Pointer))(-1) // val is a transient (temporary) string
|
||||
)
|
||||
*/
|
||||
|
||||
func (stmt *Stmt) BindText(idx Int, val string, xDel func(Pointer)) Errno {
|
||||
return stmt.doBindText(idx, c.GoStringData(val), c.Int(len(val)), xDel)
|
||||
}
|
||||
// llgo:link (*Stmt).BindText C.sqlite3_bind_text
|
||||
func (*Stmt) BindText(idx Int, val *Char, nByte Int, destructor func(Pointer)) Errno { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Reset A Prepared Statement Object
|
||||
//
|
||||
// llgo:link (*Stmt).Reset C.sqlite3_reset
|
||||
func (stmt *Stmt) Reset() Errno {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Evaluate An SQL Statement
|
||||
//
|
||||
// llgo:link (*Stmt).Step C.sqlite3_step
|
||||
@@ -208,12 +235,29 @@ func (*Stmt) Step() Errno { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// llgo:link (*Stmt).ColumnCount C.sqlite3_column_count
|
||||
func (stmt *Stmt) ColumnCount() Int { return 0 }
|
||||
|
||||
// llgo:link (*Stmt).ColumnName C.sqlite3_column_name
|
||||
func (stmt *Stmt) ColumnName(idx Int) *Char { return nil }
|
||||
|
||||
// llgo:link (*Stmt).ColumnInt C.sqlite3_column_int
|
||||
func (stmt *Stmt) ColumnInt(idx Int) Int { return 0 }
|
||||
|
||||
// llgo:link (*Stmt).ColumnInt64 C.sqlite3_column_int64
|
||||
func (stmt *Stmt) ColumnInt64(idx Int) int64 { return 0 }
|
||||
|
||||
// llgo:link (*Stmt).ColumnText C.sqlite3_column_text
|
||||
func (stmt *Stmt) ColumnText(idx Int) *Char { return nil }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// One-Step Query Execution Interface
|
||||
//
|
||||
// llgo:link (*Sqlite3).Exec C.sqlite3_exec
|
||||
func (*Sqlite3) Exec(
|
||||
sql *Char, callback func(arg Pointer, resultCols Int, colVals, colNames **Char) Int,
|
||||
arg Pointer, errmsg *Char) Errno {
|
||||
arg Pointer, errmsg **Char) Errno {
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
103
x/sqlite/sqlite.ll
Normal file
103
x/sqlite/sqlite.ll
Normal file
@@ -0,0 +1,103 @@
|
||||
; ModuleID = 'github.com/goplus/llgo/x/sqlite'
|
||||
source_filename = "github.com/goplus/llgo/x/sqlite"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@"github.com/goplus/llgo/x/sqlite.init$guard" = global ptr null
|
||||
|
||||
define ptr @"(*github.com/goplus/llgo/x/sqlite.Errno).Errstr"(ptr %0) {
|
||||
_llgo_0:
|
||||
%1 = load i32, ptr %0, align 4
|
||||
%2 = call ptr @sqlite3_errstr()
|
||||
ret ptr %2
|
||||
}
|
||||
|
||||
define { ptr, i32 } @"github.com/goplus/llgo/x/sqlite.Open"(ptr %0) {
|
||||
_llgo_0:
|
||||
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
|
||||
%2 = call i32 @sqlite3_open(ptr %0, ptr %1)
|
||||
%3 = load ptr, ptr %1, align 8
|
||||
%mrv = insertvalue { ptr, i32 } poison, ptr %3, 0
|
||||
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %2, 1
|
||||
ret { ptr, i32 } %mrv1
|
||||
}
|
||||
|
||||
define { ptr, i32 } @"github.com/goplus/llgo/x/sqlite.OpenV2"(ptr %0, i32 %1, ptr %2) {
|
||||
_llgo_0:
|
||||
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
|
||||
%4 = call i32 @sqlite3_open_v2(ptr %0, ptr %3, i32 %1, ptr %2)
|
||||
%5 = load ptr, ptr %3, align 8
|
||||
%mrv = insertvalue { ptr, i32 } poison, ptr %5, 0
|
||||
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %4, 1
|
||||
ret { ptr, i32 } %mrv1
|
||||
}
|
||||
|
||||
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)
|
||||
%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
|
||||
%mrv = insertvalue { ptr, i32 } poison, ptr %8, 0
|
||||
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %7, 1
|
||||
ret { ptr, i32 } %mrv1
|
||||
}
|
||||
|
||||
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)
|
||||
%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
|
||||
%mrv = insertvalue { ptr, i32 } poison, ptr %8, 0
|
||||
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %7, 1
|
||||
ret { ptr, i32 } %mrv1
|
||||
}
|
||||
|
||||
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)
|
||||
%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
|
||||
%mrv = insertvalue { ptr, i32 } poison, ptr %9, 0
|
||||
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %8, 1
|
||||
ret { ptr, i32 } %mrv1
|
||||
}
|
||||
|
||||
define void @"github.com/goplus/llgo/x/sqlite.init"() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"github.com/goplus/llgo/x/sqlite.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"github.com/goplus/llgo/x/sqlite.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare ptr @sqlite3_errstr()
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
|
||||
|
||||
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)
|
||||
|
||||
declare i32 @sqlite3_prepare_v3(ptr, i32, i32, ptr, ptr)
|
||||
Reference in New Issue
Block a user