Merge pull request #74 from xushiwei/q
build: skip PkgDeclOnly; cl: skip init if PkgNoInit
This commit is contained in:
@@ -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, ...)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package cl
|
package cl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"go/constant"
|
||||||
"go/types"
|
"go/types"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -24,6 +25,41 @@ import (
|
|||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestPkgNoInit(t *testing.T) {
|
||||||
|
pkg := types.NewPackage("foo", "foo")
|
||||||
|
ctx := &context{
|
||||||
|
goTyps: pkg,
|
||||||
|
loaded: make(map[*types.Package]*pkgInfo),
|
||||||
|
}
|
||||||
|
if ctx.pkgNoInit(pkg) {
|
||||||
|
t.Fatal("pkgNoInit?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPkgKind(t *testing.T) {
|
||||||
|
if v := pkgKind("noinit"); v != PkgNoInit {
|
||||||
|
t.Fatal("pkgKind:", v)
|
||||||
|
}
|
||||||
|
if v := pkgKind(""); v != PkgLLGo {
|
||||||
|
t.Fatal("pkgKind:", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPkgKindOf(t *testing.T) {
|
||||||
|
if v := PkgKindOf(types.Unsafe); v != PkgDeclOnly {
|
||||||
|
t.Fatal("PkgKindOf unsafe:", v)
|
||||||
|
}
|
||||||
|
pkg := types.NewPackage("foo", "foo")
|
||||||
|
pkg.Scope().Insert(
|
||||||
|
types.NewConst(
|
||||||
|
0, pkg, "LLGoPackage", types.Typ[types.String],
|
||||||
|
constant.MakeString("noinit")),
|
||||||
|
)
|
||||||
|
if v := PkgKindOf(pkg); v != PkgNoInit {
|
||||||
|
t.Fatal("PkgKindOf foo:", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsAny(t *testing.T) {
|
func TestIsAny(t *testing.T) {
|
||||||
if isAny(types.Typ[types.UntypedInt]) {
|
if isAny(types.Typ[types.UntypedInt]) {
|
||||||
t.Fatal("isAny?")
|
t.Fatal("isAny?")
|
||||||
@@ -48,7 +84,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) {
|
||||||
|
|||||||
@@ -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 >= PkgNoInit
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -113,13 +113,22 @@ 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
|
||||||
|
PkgLLGo
|
||||||
|
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 +138,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 +280,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 +493,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: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ctx.initFiles(pkgPath, files)
|
ctx.initFiles(pkgPath, files)
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
|
|||||||
54
cl/import.go
54
cl/import.go
@@ -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,45 @@ func contentOf(m contentMap, file string) (lines contentLines, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) importPkg(pkg *types.Package) {
|
// PkgKindOf returns the kind of a package.
|
||||||
|
func PkgKindOf(pkg *types.Package) int {
|
||||||
scope := pkg.Scope()
|
scope := pkg.Scope()
|
||||||
if scope.Lookup("LLGoPackage") == nil {
|
kind := pkgKindByScope(scope)
|
||||||
|
if kind == PkgNormal {
|
||||||
|
kind = pkgKindByPath(pkg.Path())
|
||||||
|
}
|
||||||
|
return kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 PkgLLGo
|
||||||
|
}
|
||||||
|
|
||||||
|
func pkgKindByScope(scope *types.Scope) int {
|
||||||
|
if v, ok := scope.Lookup("LLGoPackage").(*types.Const); ok {
|
||||||
|
if v := v.Val(); v.Kind() == constant.String {
|
||||||
|
return pkgKind(constant.StringVal(v))
|
||||||
|
}
|
||||||
|
return PkgLLGo
|
||||||
|
}
|
||||||
|
return PkgNormal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
|
||||||
|
scope := pkg.Scope()
|
||||||
|
kind := pkgKindByScope(scope)
|
||||||
|
if kind == PkgNormal {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
i.kind = kind
|
||||||
fset := p.fset
|
fset := p.fset
|
||||||
names := scope.Names()
|
names := scope.Names()
|
||||||
contents := make(contentMap)
|
contents := make(contentMap)
|
||||||
@@ -170,9 +205,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", "unsafe":
|
||||||
|
return PkgDeclOnly
|
||||||
|
}
|
||||||
|
return PkgNormal
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod
|
|||||||
args[2] = "-Wno-override-module"
|
args[2] = "-Wno-override-module"
|
||||||
needRuntime := false
|
needRuntime := false
|
||||||
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||||
if p.PkgPath != "unsafe" { // TODO(xsw): maybe can remove this special case
|
if p.ExportFile != "" { // skip packages that only contain declarations
|
||||||
args = append(args, p.ExportFile+".ll")
|
args = append(args, p.ExportFile+".ll")
|
||||||
if !needRuntime {
|
if !needRuntime {
|
||||||
needRuntime = isNeedRuntime(p)
|
needRuntime = isNeedRuntime(p)
|
||||||
@@ -220,6 +220,12 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod
|
|||||||
|
|
||||||
func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode, verbose bool) {
|
func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode, verbose bool) {
|
||||||
pkg := aPkg.Package
|
pkg := aPkg.Package
|
||||||
|
if cl.PkgKindOf(pkg.Types) == cl.PkgDeclOnly {
|
||||||
|
// skip packages that only contain declarations
|
||||||
|
// and set no export file
|
||||||
|
pkg.ExportFile = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
pkgPath := pkg.PkgPath
|
pkgPath := pkg.PkgPath
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Fprintln(os.Stderr, pkgPath)
|
fmt.Fprintln(os.Stderr, pkgPath)
|
||||||
@@ -320,7 +326,7 @@ func allLinkFiles(rt []*packages.Package) (outFiles []string) {
|
|||||||
outFiles = make([]string, 0, len(rt))
|
outFiles = make([]string, 0, len(rt))
|
||||||
root := rootLLGo(rt[0])
|
root := rootLLGo(rt[0])
|
||||||
packages.Visit(rt, nil, func(p *packages.Package) {
|
packages.Visit(rt, nil, func(p *packages.Package) {
|
||||||
if isPkgInLLGo(p.PkgPath) {
|
if hasLinkFile(p) {
|
||||||
outFile := filepath.Join(root+p.PkgPath[len(llgoModPath):], "llgo_autogen.ll")
|
outFile := filepath.Join(root+p.PkgPath[len(llgoModPath):], "llgo_autogen.ll")
|
||||||
outFiles = append(outFiles, outFile)
|
outFiles = append(outFiles, outFile)
|
||||||
}
|
}
|
||||||
@@ -328,6 +334,13 @@ func allLinkFiles(rt []*packages.Package) (outFiles []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasLinkFile(pkg *packages.Package) bool {
|
||||||
|
if isPkgInLLGo(pkg.PkgPath) {
|
||||||
|
return cl.PkgKindOf(pkg.Types) != cl.PkgDeclOnly
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(xsw): llgo root dir
|
// TODO(xsw): llgo root dir
|
||||||
func rootLLGo(runtime *packages.Package) string {
|
func rootLLGo(runtime *packages.Package) string {
|
||||||
return runtime.Module.Dir
|
return runtime.Module.Dir
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -172,8 +172,6 @@ _llgo_0:
|
|||||||
ret %"github.com/goplus/llgo/internal/runtime.iface" %12
|
ret %"github.com/goplus/llgo/internal/runtime.iface" %12
|
||||||
}
|
}
|
||||||
|
|
||||||
declare ptr @malloc(i64)
|
|
||||||
|
|
||||||
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NilSlice"() {
|
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NilSlice"() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
%0 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||||
@@ -267,4 +265,6 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare ptr @malloc(i64)
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/abi.init"()
|
declare void @"github.com/goplus/llgo/internal/abi.init"()
|
||||||
|
|||||||
44
internal/runtime/z_c.go
Normal file
44
internal/runtime/z_c.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
Reference in New Issue
Block a user