cl: pkgKind = normal/noinit/decl

This commit is contained in:
xushiwei
2024-04-29 09:51:32 +08:00
parent 7979cfcb06
commit b45172bef1
7 changed files with 115 additions and 26 deletions

View File

@@ -11,7 +11,6 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 store i1 true, ptr @"main.init$guard", align 1
call void @"github.com/goplus/llgo/cl/internal/libc.init"()
store i8 72, ptr @main.format, align 1 store i8 72, ptr @main.format, align 1
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1 store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1 store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
@@ -36,8 +35,6 @@ _llgo_0:
ret void ret void
} }
declare void @"github.com/goplus/llgo/cl/internal/libc.init"()
declare i32 @strlen(ptr) declare i32 @strlen(ptr)
declare void @"github.com/goplus/llgo/cl/internal/libc.Printf"(ptr, ...) declare void @"github.com/goplus/llgo/cl/internal/libc.Printf"(ptr, ...)

View File

@@ -48,7 +48,7 @@ func TestIgnoreName(t *testing.T) {
func TestErrImport(t *testing.T) { func TestErrImport(t *testing.T) {
var ctx context var ctx context
pkg := types.NewPackage("foo", "foo") pkg := types.NewPackage("foo", "foo")
ctx.importPkg(pkg) ctx.importPkg(pkg, nil)
} }
func TestErrInitLinkname(t *testing.T) { func TestErrInitLinkname(t *testing.T) {

View File

@@ -61,12 +61,12 @@ const (
fnIgnore fnIgnore
) )
func funcKind(vfn ssa.Value) int { func (p *context) funcKind(vfn ssa.Value) int {
if fn, ok := vfn.(*ssa.Function); ok && fn.Signature.Recv() == nil { if fn, ok := vfn.(*ssa.Function); ok && fn.Signature.Recv() == nil {
params := fn.Signature.Params() params := fn.Signature.Params()
n := params.Len() n := params.Len()
if n == 0 { if n == 0 {
if fn.Name() == "init" && ignorePkgInit(fn.Pkg.Pkg.Path()) { if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) {
return fnIgnore return fnIgnore
} }
} else { } else {
@@ -79,10 +79,10 @@ func funcKind(vfn ssa.Value) int {
return fnNormal return fnNormal
} }
func ignorePkgInit(pkgPath string) bool { func (p *context) pkgNoInit(pkg *types.Package) bool {
switch pkgPath { p.ensureLoaded(pkg)
case "unsafe", "syscall", "runtime/cgo": if i, ok := p.loaded[pkg]; ok {
return true return i.kind != pkgNormal
} }
return false return false
} }
@@ -113,13 +113,21 @@ func inPkg(name, pkg string) bool {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type none = struct{}
type instrOrValue interface { type instrOrValue interface {
ssa.Instruction ssa.Instruction
ssa.Value ssa.Value
} }
const (
pkgNormal = iota
pkgNoInit // noinit: a package that don't need to be initialized
pkgDeclOnly // decl: a package that only have declarations
)
type pkgInfo struct {
kind int
}
type context struct { type context struct {
prog llssa.Program prog llssa.Program
pkg llssa.Package pkg llssa.Package
@@ -129,7 +137,7 @@ type context struct {
goTyps *types.Package goTyps *types.Package
goPkg *ssa.Package goPkg *ssa.Package
link map[string]string // pkgPath.nameInPkg => linkname link map[string]string // pkgPath.nameInPkg => linkname
loaded map[*types.Package]none // loaded packages loaded map[*types.Package]*pkgInfo // loaded packages
bvals map[ssa.Value]llssa.Expr // block values bvals map[ssa.Value]llssa.Expr // block values
vargs map[*ssa.Alloc][]llssa.Expr // varargs vargs map[*ssa.Alloc][]llssa.Expr // varargs
inits []func() inits []func()
@@ -271,7 +279,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
case *ssa.Call: case *ssa.Call:
call := v.Call call := v.Call
cv := call.Value cv := call.Value
kind := funcKind(cv) kind := p.funcKind(cv)
if kind == fnIgnore { if kind == fnIgnore {
return return
} }
@@ -484,8 +492,10 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
goTyps: pkgTypes, goTyps: pkgTypes,
goPkg: pkg, goPkg: pkg,
link: make(map[string]string), link: make(map[string]string),
loaded: make(map[*types.Package]none),
vargs: make(map[*ssa.Alloc][]llssa.Expr), vargs: make(map[*ssa.Alloc][]llssa.Expr),
loaded: map[*types.Package]*pkgInfo{
types.Unsafe: {kind: pkgNoInit}, // TODO(xsw): pkgNoInit or pkgDeclOnly?
},
} }
ctx.initFiles(pkgPath, files) ctx.initFiles(pkgPath, files)
for _, m := range members { for _, m := range members {

View File

@@ -19,6 +19,7 @@ package cl
import ( import (
"bytes" "bytes"
"go/ast" "go/ast"
"go/constant"
"go/token" "go/token"
"go/types" "go/types"
"os" "os"
@@ -43,11 +44,27 @@ func contentOf(m contentMap, file string) (lines contentLines, err error) {
return return
} }
func (p *context) importPkg(pkg *types.Package) { // decl: a package that only contains declarations
// noinit: a package that does not need to be initialized
func pkgKind(v string) int {
switch v {
case "decl":
return pkgDeclOnly
case "noinit":
return pkgNoInit
}
return pkgNormal
}
func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
scope := pkg.Scope() scope := pkg.Scope()
if scope.Lookup("LLGoPackage") == nil { llpkg, ok := scope.Lookup("LLGoPackage").(*types.Const)
if !ok {
return return
} }
if v := llpkg.Val(); v.Kind() == constant.String {
i.kind = pkgKind(constant.StringVal(v))
}
fset := p.fset fset := p.fset
names := scope.Names() names := scope.Names()
contents := make(contentMap) contents := make(contentMap)
@@ -170,9 +187,20 @@ func (p *context) varOf(v *ssa.Global) llssa.Global {
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package { func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {
if p.goTyps != pkgTypes { if p.goTyps != pkgTypes {
if _, ok := p.loaded[pkgTypes]; !ok { if _, ok := p.loaded[pkgTypes]; !ok {
p.loaded[pkgTypes] = none{} i := &pkgInfo{
p.importPkg(pkgTypes) kind: pkgKindByPath(pkgTypes.Path()),
}
p.loaded[pkgTypes] = i
p.importPkg(pkgTypes, i)
} }
} }
return pkgTypes return pkgTypes
} }
func pkgKindByPath(pkgPath string) int {
switch pkgPath {
case "syscall", "runtime/cgo":
return pkgNoInit
}
return pkgNormal
}

View File

@@ -4,7 +4,7 @@ import "C"
import _ "unsafe" import _ "unsafe"
const ( const (
LLGoPackage = true LLGoPackage = "decl"
) )
//go:linkname Printf C.printf //go:linkname Printf C.printf

View File

@@ -14,18 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
package runtime package c
import "unsafe" import "unsafe"
const ( const (
LLGoPackage = true LLGoPackage = "decl"
) )
//go:linkname String llgo.CString
func String(string) *int8
//go:linkname Alloca llgo.Alloca
func Alloca(size uintptr) unsafe.Pointer
//go:linkname Unreachable llgo.Unreachable
func Unreachable()
//go:linkname Malloc C.malloc //go:linkname Malloc C.malloc
func Malloc(size uintptr) unsafe.Pointer func Malloc(size uintptr) unsafe.Pointer
// Alloc allocates memory. //go:linkname Memcpy C.memcpy
func Alloc(size uintptr) unsafe.Pointer { func Memcpy(dst, src unsafe.Pointer, n uintptr) unsafe.Pointer
return Malloc(size)
} //go:linkname Printf C.printf
func Printf(format *int8, __llgo_va_list ...any)

44
internal/runtime/z_c.go Normal file
View File

@@ -0,0 +1,44 @@
/*
* 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 runtime
import (
"unsafe"
"github.com/goplus/llgo/internal/runtime/c"
)
// Alloc allocates memory.
func Alloc(size uintptr) unsafe.Pointer {
return c.Malloc(size)
}
/*
// Panic panics with a value.
func Panic(v Interface) {
c.Printf(c.String("Panic!!!\n"))
kind := abi.Kind(v.tab._type.Kind_)
switch {
case kind == abi.String:
s := (*String)(v.data)
cs := c.Alloca(uintptr(s.len) + 1)
c.Memcpy(cs, s.data, uintptr(s.len))
(*[1 << 30]int8)(cs)[s.len] = 0
c.Printf(c.String("%s\n"), cs)
}
}
*/