Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 0 additions & 63 deletions cl/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,69 +447,6 @@ func TestErrVarOf(t *testing.T) {
ctx.varOf(nil, g)
}

func TestContextResolveLinkname(t *testing.T) {
tests := []struct {
name string
link map[string]string
input string
want string
panics bool
}{
{
name: "Normal",
link: map[string]string{
"foo": "C.bar",
},
input: "foo",
want: "bar",
},
{
name: "MultipleLinks",
link: map[string]string{
"foo1": "C.bar1",
"foo2": "C.bar2",
},
input: "foo2",
want: "bar2",
},
{
name: "NoLink",
link: map[string]string{},
input: "foo",
want: "foo",
},
{
name: "InvalidLink",
link: map[string]string{
"foo": "invalid.bar",
},
input: "foo",
panics: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.panics {
defer func() {
if r := recover(); r == nil {
t.Error("want panic")
}
}()
}
ctx := &context{prog: llssa.NewProgram(nil)}
for k, v := range tt.link {
ctx.prog.SetLinkname(k, v)
}
got := ctx.resolveLinkname(tt.input)
if !tt.panics {
if got != tt.want {
t.Errorf("got %q, want %q", got, tt.want)
}
}
})
}
}

func TestInstantiate(t *testing.T) {
obj := types.NewTypeName(0, nil, "T", nil)
named := types.NewNamed(obj, types.Typ[types.Int], nil)
Expand Down
13 changes: 1 addition & 12 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,7 @@ func newPackageEx(prog llssa.Program, patches Patches, rewrites map[string]strin
ctx.initFiles(pkgPath, files, pkgName == "C")
ctx.prog.SetPatch(ctx.patchType)
ctx.prog.SetCompileMethods(ctx.checkCompileMethods)
ret.SetResolveLinkname(ctx.resolveLinkname)
ret.SetResolveLinkname(ctx.prog.ResolveLinkname)

if hasPatch {
skips := ctx.skips
Expand Down Expand Up @@ -1349,17 +1349,6 @@ func instantiate(orig types.Type, t *types.Named) (typ types.Type) {
return
}

func (p *context) resolveLinkname(name string) string {
if link, ok := p.prog.Linkname(name); ok {
prefix, ltarget, _ := strings.Cut(link, ".")
if prefix != "C" {
panic("resolveLinkname: invalid link: " + link)
}
return ltarget
}
return name
}

// checkCompileMethods ensures that all methods attached to the given type
// (and to the types it refers to) are compiled and emitted into the
// current SSA package. Generic named types and struct types are the
Expand Down
1 change: 1 addition & 0 deletions cl/instr.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ func (p *context) pkgNoInit(pkg *types.Package) bool {
func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) {
cv := call.Value
if mthd := call.Method; mthd != nil {
p.prog.AddInvoke(mthd)
o := p.compileValue(b, cv)
fn := b.Imethod(o, mthd)
hasVArg := fnNormal
Expand Down
22 changes: 17 additions & 5 deletions internal/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,9 @@ func compileExtraFiles(ctx *context, verbose bool) ([]string, error) {
func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPath string, verbose bool) error {
needRuntime := false
needPyInit := false
needAbiInit := false
var needAbiInit int
methodByIndex := make(map[int]none)
methodByName := make(map[string]none)
allPkgs := []*packages.Package{pkg}
for _, v := range pkgs {
allPkgs = append(allPkgs, v.Package)
Expand Down Expand Up @@ -926,10 +928,13 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa
needRuntime = needRuntime || need1
needPyInit = needPyInit || need2
}
if aPkg.LPkg.NeedAbiInit {
needAbiInit = true
needAbiInit |= aPkg.LPkg.NeedAbiInit
for k, _ := range aPkg.LPkg.MethodByIndex {
methodByIndex[k] = none{}
}
for k, _ := range aPkg.LPkg.MethodByName {
methodByName[k] = none{}
}

linkArgs = append(linkArgs, aPkg.LinkArgs...)
if aPkg.ArchiveFile != "" {
linkInputs = append(linkInputs, aPkg.ArchiveFile)
Expand All @@ -946,7 +951,14 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa
// Generate main module file (needed for global variables even in library modes)
// This is compiled directly to .o and added to linkInputs (not cached)
// Use a stable synthetic name to avoid confusing it with the real main package in traces/logs.
entryPkg := genMainModule(ctx, llssa.PkgRuntime, pkg, needRuntime, needPyInit, needAbiInit)
entryPkg := genMainModule(ctx, llssa.PkgRuntime, pkg, &genConfig{
rtInit: needRuntime,
pyInit: needPyInit,
abiInit: needAbiInit,
abiPrune: !IsDbgEnabled(),
methodByIndex: methodByIndex,
methodByName: methodByName,
})
entryObjFile, err := exportObject(ctx, "entry_main", entryPkg.ExportFile, []byte(entryPkg.LPkg.String()))
if err != nil {
return err
Expand Down
107 changes: 100 additions & 7 deletions internal/build/main_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,34 @@
package build

import (
"go/ast"
"go/token"
"go/types"

"github.com/goplus/llgo/internal/packages"
llvm "github.com/goplus/llvm"

llssa "github.com/goplus/llgo/ssa"
llvm "github.com/goplus/llvm"
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/callgraph/cha"
"golang.org/x/tools/go/ssa"
)

// genConfig controls the code generation behavior for the main module.
type genConfig struct {
rtInit bool
pyInit bool
abiInit int
abiPrune bool
methodByIndex map[int]none
methodByName map[string]none
}

// genMainModule generates the main entry module for an llgo program.
//
// The module contains argc/argv globals and, for executable build modes,
// the entry function that wires initialization and main. For C archive or
// shared library modes, only the globals are emitted.
func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRuntime, needPyInit, needAbiInit bool) Package {
func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, cfg *genConfig) Package {
prog := ctx.prog
mainPkg := prog.NewPackage("", pkg.ID+".main")

Expand Down Expand Up @@ -73,18 +86,66 @@ func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRu
defineWeakNoArgStub(mainPkg, "syscall.init")

var pyInit llssa.Function
if needPyInit {
if cfg.pyInit {
pyInit = declareNoArgFunc(mainPkg, "Py_Initialize")
}

var rtInit llssa.Function
if needRuntime {
if cfg.rtInit {
rtInit = declareNoArgFunc(mainPkg, rtPkgPath+".init")
}

if cfg.abiPrune {
progSSA := ctx.progSSA
/*
// RTA has issues parsing the patch package
res := buildRTAResult(progSSA)
invoked := buildInvokeIndex(res.CallGraph)
*/
cg := cha.CallGraph(progSSA)
invoked := buildInvokeIndex(cg)
mainPkg.PruneAbiTypes(cfg.abiInit, func(index int, method *types.Selection) bool {
name := method.Obj().Name()
if ast.IsExported(name) {
if cfg.abiInit&llssa.ReflectMethodDynamic != 0 {
return true
} else {
if cfg.abiInit&llssa.ReflectMethodByIndex != 0 {
if _, ok := cfg.methodByIndex[index]; ok {
return true
}
}
if cfg.abiInit&llssa.ReflectMethodByName != 0 {
if _, ok := cfg.methodByName[name]; ok {
return true
}
}
}
}
mth := progSSA.MethodValue(method)
if _, ok := invoked[mth]; ok {
return true
}
mtyp := method.Type()
for v := range invoked {
if v.Name() == mth.Name() {
vtyp := v.Type()
if !types.Identical(prog.Patch(vtyp.(*types.Signature).Recv().Type()), mtyp.(*types.Signature).Recv().Type()) {
continue
}
if !types.Identical(prog.Patch(vtyp), mtyp) {
continue
}
return true
}
}
return false
})
}

var abiInit llssa.Function
if needAbiInit {
abiInit = mainPkg.InitAbiTypes("init$abitypes")
if cfg.abiInit != 0 {
abiInit = mainPkg.InitAbiTypes(cfg.abiInit, "init$abitypes")
}

mainInit := declareNoArgFunc(mainPkg, pkg.PkgPath+".init")
Expand All @@ -99,6 +160,38 @@ func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRu
return mainAPkg
}

/*
func buildRTAResult(progSSA *ssa.Program) *rta.Result {
var roots []*ssa.Function
for _, pkg := range progSSA.AllPackages() {
if pkg.Pkg.Name() == "main" {
if fn := pkg.Func("main"); fn != nil {
roots = append(roots, fn)
}
}
if fn := pkg.Func("init"); fn != nil {
roots = append(roots, fn)
}
}
res := rta.Analyze(roots, true)
return res
}
*/

func buildInvokeIndex(cg *callgraph.Graph) map[*ssa.Function]bool {
invoked := make(map[*ssa.Function]bool)
for _, node := range cg.Nodes {
for _, out := range node.Out {
if out.Callee != nil && out.Callee.Func != nil {
if out.Site != nil && out.Site.Common().IsInvoke() {
invoked[out.Callee.Func] = true
}
}
}
}
return invoked
}

// defineEntryFunction creates the program's entry function. The name is
// "main" for standard targets, or "__main_argc_argv" with hidden visibility
// for WASM targets that don't require _start.
Expand Down
4 changes: 2 additions & 2 deletions internal/build/main_module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestGenMainModuleExecutable(t *testing.T) {
},
}
pkg := &packages.Package{PkgPath: "example.com/foo", ExportFile: "foo.a"}
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, true, true, true)
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, &genConfig{rtInit: true, pyInit: true, abiInit: llssa.ReflectMethodDynamic})
if mod.ExportFile != "foo.a-main" {
t.Fatalf("unexpected export file: %s", mod.ExportFile)
}
Expand Down Expand Up @@ -59,7 +59,7 @@ func TestGenMainModuleLibrary(t *testing.T) {
},
}
pkg := &packages.Package{PkgPath: "example.com/foo", ExportFile: "foo.a"}
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, false, false, false)
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, &genConfig{})
ir := mod.LPkg.String()
if strings.Contains(ir, "define i32 @main") {
t.Fatalf("library mode should not emit main function:\n%s", ir)
Expand Down
Loading
Loading