9
cl/_testrt/concat/in.go
Normal file
9
cl/_testrt/concat/in.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llgo/internal/runtime/c"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c.Fprintf(c.Stderr, c.Str("Hello %d\n"), 100)
|
||||||
|
}
|
||||||
32
cl/_testrt/concat/out.ll
Normal file
32
cl/_testrt/concat/out.ll
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
@__stderrp = external global ptr
|
||||||
|
@0 = private unnamed_addr constant [10 x i8] c"Hello %d\0A\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
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
call void @main.init()
|
||||||
|
%0 = load ptr, ptr @__stderrp, align 8
|
||||||
|
%1 = call i32 (ptr, ptr, ...) @fprintf(ptr %0, ptr @0, i64 100)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
|
||||||
|
declare i32 @fprintf(ptr, ptr, ...)
|
||||||
16
cl/_testrt/fprintf/in.go
Normal file
16
cl/_testrt/fprintf/in.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:linkname cstr llgo.cstr
|
||||||
|
func cstr(string) *int8
|
||||||
|
|
||||||
|
//go:linkname stderr __stderrp
|
||||||
|
var stderr unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname fprintf C.fprintf
|
||||||
|
func fprintf(fp unsafe.Pointer, format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fprintf(stderr, cstr("Hello %d\n"), 100)
|
||||||
|
}
|
||||||
32
cl/_testrt/fprintf/out.ll
Normal file
32
cl/_testrt/fprintf/out.ll
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
@__stderrp = external global ptr
|
||||||
|
@0 = private unnamed_addr constant [10 x i8] c"Hello %d\0A\00", align 1
|
||||||
|
|
||||||
|
declare void @fprintf(ptr, ptr, ...)
|
||||||
|
|
||||||
|
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() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
call void @main.init()
|
||||||
|
%0 = load ptr, ptr @__stderrp, align 8
|
||||||
|
call void (ptr, ptr, ...) @fprintf(ptr %0, ptr @0, i64 100)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
@@ -122,7 +122,7 @@ func TestErrInitLinkname(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
var ctx context
|
var ctx context
|
||||||
ctx.initLinkname("foo", "//go:linkname Printf printf")
|
ctx.initLinkname("foo", "//go:linkname Printf printf", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrVarOf(t *testing.T) {
|
func TestErrVarOf(t *testing.T) {
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
|||||||
// Global variable.
|
// Global variable.
|
||||||
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
||||||
typ := gbl.Type()
|
typ := gbl.Type()
|
||||||
name := llssa.FullName(gbl.Pkg.Pkg, gbl.Name())
|
name, isDef := p.varName(gbl.Pkg.Pkg, gbl)
|
||||||
if ignoreName(name) || checkCgo(gbl.Name()) {
|
if ignoreName(name) || checkCgo(gbl.Name()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,9 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
|||||||
log.Println("==> NewVar", name, typ)
|
log.Println("==> NewVar", name, typ)
|
||||||
}
|
}
|
||||||
g := pkg.NewVar(name, typ)
|
g := pkg.NewVar(name, typ)
|
||||||
g.Init(p.prog.Null(g.Type))
|
if isDef {
|
||||||
|
g.Init(p.prog.Null(g.Type))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
|
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
|
||||||
|
|||||||
78
cl/import.go
78
cl/import.go
@@ -90,19 +90,14 @@ func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
|
|||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if token.IsExported(name) {
|
if token.IsExported(name) {
|
||||||
obj := scope.Lookup(name)
|
obj := scope.Lookup(name)
|
||||||
if obj, ok := obj.(*types.Func); ok {
|
switch obj := obj.(type) {
|
||||||
|
case *types.Func:
|
||||||
if pos := obj.Pos(); pos != token.NoPos {
|
if pos := obj.Pos(); pos != token.NoPos {
|
||||||
f := fset.File(pos)
|
p.initLinknameByPos(fset, pos, pkgPath, contents, false)
|
||||||
if fp := f.Position(pos); fp.Line > 2 {
|
}
|
||||||
lines, err := contentOf(contents, fp.Filename)
|
case *types.Var:
|
||||||
if err != nil {
|
if pos := obj.Pos(); pos != token.NoPos {
|
||||||
panic(err)
|
p.initLinknameByPos(fset, pos, pkgPath, contents, true)
|
||||||
}
|
|
||||||
if i := fp.Line - 2; i < len(lines) {
|
|
||||||
line := string(lines[i])
|
|
||||||
p.initLinkname(pkgPath, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,21 +107,44 @@ func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
|
|||||||
func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
for _, decl := range file.Decls {
|
for _, decl := range file.Decls {
|
||||||
if decl, ok := decl.(*ast.FuncDecl); ok {
|
switch decl := decl.(type) {
|
||||||
|
case *ast.FuncDecl:
|
||||||
if decl.Recv == nil {
|
if decl.Recv == nil {
|
||||||
if doc := decl.Doc; doc != nil {
|
p.initLinknameByDoc(decl.Doc, pkgPath, false)
|
||||||
if n := len(doc.List); n > 0 {
|
}
|
||||||
line := doc.List[n-1].Text
|
case *ast.GenDecl:
|
||||||
p.initLinkname(pkgPath, line)
|
if decl.Tok == token.VAR && len(decl.Specs) == 1 {
|
||||||
}
|
p.initLinknameByDoc(decl.Doc, pkgPath, true)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) initLinkname(pkgPath, line string) {
|
func (p *context) initLinknameByDoc(doc *ast.CommentGroup, pkgPath string, isVar bool) {
|
||||||
|
if doc != nil {
|
||||||
|
if n := len(doc.List); n > 0 {
|
||||||
|
line := doc.List[n-1].Text
|
||||||
|
p.initLinkname(pkgPath, line, isVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) initLinknameByPos(fset *token.FileSet, pos token.Pos, pkgPath string, contents contentMap, isVar bool) {
|
||||||
|
f := fset.File(pos)
|
||||||
|
if fp := f.Position(pos); fp.Line > 2 {
|
||||||
|
lines, err := contentOf(contents, fp.Filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if i := fp.Line - 2; i < len(lines) {
|
||||||
|
line := string(lines[i])
|
||||||
|
p.initLinkname(pkgPath, line, isVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) initLinkname(pkgPath, line string, isVar bool) {
|
||||||
const (
|
const (
|
||||||
linkname = "//go:linkname "
|
linkname = "//go:linkname "
|
||||||
)
|
)
|
||||||
@@ -134,7 +152,7 @@ func (p *context) initLinkname(pkgPath, line string) {
|
|||||||
text := strings.TrimSpace(line[len(linkname):])
|
text := strings.TrimSpace(line[len(linkname):])
|
||||||
if idx := strings.IndexByte(text, ' '); idx > 0 {
|
if idx := strings.IndexByte(text, ' '); idx > 0 {
|
||||||
link := strings.TrimLeft(text[idx+1:], " ")
|
link := strings.TrimLeft(text[idx+1:], " ")
|
||||||
if strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr
|
if isVar || strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr
|
||||||
name := pkgPath + "." + text[:idx]
|
name := pkgPath + "." + text[:idx]
|
||||||
p.link[name] = link
|
p.link[name] = link
|
||||||
} else {
|
} else {
|
||||||
@@ -201,6 +219,14 @@ func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (s
|
|||||||
return name, goFunc
|
return name, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *context) varName(pkg *types.Package, v *ssa.Global) (vName string, isDef bool) {
|
||||||
|
name := llssa.FullName(pkg, v.Name())
|
||||||
|
if v, ok := p.link[name]; ok {
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
return name, true
|
||||||
|
}
|
||||||
|
|
||||||
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
||||||
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
||||||
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
||||||
@@ -226,14 +252,14 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) varOf(v *ssa.Global) llssa.Global {
|
func (p *context) varOf(v *ssa.Global) (ret llssa.Global) {
|
||||||
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
|
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
|
||||||
pkg := p.pkg
|
pkg := p.pkg
|
||||||
name := llssa.FullName(pkgTypes, v.Name())
|
name, _ := p.varName(pkgTypes, v)
|
||||||
if ret := pkg.VarOf(name); ret != nil {
|
if ret = pkg.VarOf(name); ret == nil {
|
||||||
return ret
|
ret = pkg.NewVar(name, v.Type())
|
||||||
}
|
}
|
||||||
return pkg.NewVar(name, v.Type())
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {
|
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {
|
||||||
|
|||||||
@@ -27,8 +27,18 @@ type (
|
|||||||
Char = int8
|
Char = int8
|
||||||
Int = C.int
|
Int = C.int
|
||||||
Pointer = unsafe.Pointer
|
Pointer = unsafe.Pointer
|
||||||
|
FilePtr = unsafe.Pointer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:linkname Stdin __stdinp
|
||||||
|
var Stdin FilePtr
|
||||||
|
|
||||||
|
//go:linkname Stdout __stdoutp
|
||||||
|
var Stdout FilePtr
|
||||||
|
|
||||||
|
//go:linkname Stderr __stderrp
|
||||||
|
var Stderr FilePtr
|
||||||
|
|
||||||
//go:linkname Str llgo.cstr
|
//go:linkname Str llgo.cstr
|
||||||
func Str(string) *Char
|
func Str(string) *Char
|
||||||
|
|
||||||
@@ -52,3 +62,6 @@ func Memcpy(dst, src Pointer, n uintptr) Pointer
|
|||||||
|
|
||||||
//go:linkname Printf C.printf
|
//go:linkname Printf C.printf
|
||||||
func Printf(format *Char, __llgo_va_list ...any) Int
|
func Printf(format *Char, __llgo_va_list ...any) Int
|
||||||
|
|
||||||
|
//go:linkname Fprintf C.fprintf
|
||||||
|
func Fprintf(fp FilePtr, format *Char, __llgo_va_list ...any) Int
|
||||||
|
|||||||
Reference in New Issue
Block a user