Merge pull request #91 from xushiwei/q

cl: support stdin/stdout/stderr
This commit is contained in:
xushiwei
2024-05-01 21:26:20 +08:00
committed by GitHub
8 changed files with 159 additions and 29 deletions

9
cl/_testrt/concat/in.go Normal file
View 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
View 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
View 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
View 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"()

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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