Skip to content

Commit 3e6798c

Browse files
committed
ssa: prune abitypes by callgraph
1 parent ba842c4 commit 3e6798c

File tree

5 files changed

+240
-22
lines changed

5 files changed

+240
-22
lines changed

cl/instr.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ func (p *context) pkgNoInit(pkg *types.Package) bool {
507507
func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) {
508508
cv := call.Value
509509
if mthd := call.Method; mthd != nil {
510+
p.prog.AddInvoke(mthd)
510511
o := p.compileValue(b, cv)
511512
fn := b.ImethodEx(o, mthd, act != llssa.Call)
512513
hasVArg := fnNormal

internal/build/main_module.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ import (
3232

3333
"github.com/goplus/llgo/internal/packages"
3434
llvm "github.com/goplus/llvm"
35+
"golang.org/x/tools/go/callgraph"
36+
"golang.org/x/tools/go/callgraph/cha"
37+
"golang.org/x/tools/go/ssa"
3538

3639
llssa "github.com/goplus/llgo/ssa"
3740
)
@@ -82,6 +85,32 @@ func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRu
8285
rtInit = declareNoArgFunc(mainPkg, rtPkgPath+".init")
8386
}
8487

88+
if !needAbiInit {
89+
progSSA := ctx.progSSA
90+
chaGraph := cha.CallGraph(progSSA)
91+
//vtaGraph := vta.CallGraph(ssautil.AllFunctions(progSSA), chaGraph)
92+
//_ = vtaGraph
93+
invoked := buildInvokeIndex(chaGraph)
94+
mainPkg.PruneAbiTypes(func(sel *types.Selection) bool {
95+
method := progSSA.MethodValue(sel)
96+
if _, ok := invoked[method]; ok {
97+
return true
98+
}
99+
for v := range invoked {
100+
if v.Name() == method.Name() {
101+
if !types.Identical(prog.PatchType(v.Type().(*types.Signature).Recv().Type()), sel.Type().(*types.Signature).Recv().Type()) {
102+
continue
103+
}
104+
if !types.Identical(prog.PatchType(v.Type()), sel.Type()) {
105+
continue
106+
}
107+
return true
108+
}
109+
}
110+
return false
111+
})
112+
}
113+
85114
var abiInit llssa.Function
86115
if needAbiInit {
87116
abiInit = mainPkg.InitAbiTypes("init$abitypes")
@@ -99,6 +128,20 @@ func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRu
99128
return mainAPkg
100129
}
101130

131+
func buildInvokeIndex(cg *callgraph.Graph) map[*ssa.Function]bool {
132+
invoked := make(map[*ssa.Function]bool)
133+
for _, node := range cg.Nodes {
134+
for _, out := range node.Out {
135+
if out.Callee != nil && out.Callee.Func != nil {
136+
if out.Site != nil && out.Site.Common().IsInvoke() {
137+
invoked[out.Callee.Func] = true
138+
}
139+
}
140+
}
141+
}
142+
return invoked
143+
}
144+
102145
// defineEntryFunction creates the program's entry function. The name is
103146
// "main" for standard targets, or "__main_argc_argv" with hidden visibility
104147
// for WASM targets that don't require _start.

ssa/abitype.go

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -347,14 +347,14 @@ func (b Builder) abiUncommonMethodSet(t types.Type) (mset *types.MethodSet, ok b
347347
}
348348
mset := types.NewMethodSet(t)
349349
if mset.Len() != 0 {
350-
if prog.compileMethods != nil {
350+
if prog.compileMethods != nil && !prog.abiTypePruning {
351351
prog.compileMethods(b.Pkg, t)
352352
}
353353
}
354354
return mset, true
355355
case *types.Struct, *types.Pointer:
356356
if mset := types.NewMethodSet(t); mset.Len() != 0 {
357-
if prog.compileMethods != nil {
357+
if prog.compileMethods != nil && !prog.abiTypePruning {
358358
prog.compileMethods(b.Pkg, t)
359359
}
360360
return mset, true
@@ -372,7 +372,7 @@ type UncommonType struct {
372372
}
373373
*/
374374

375-
func (b Builder) abiUncommonType(t types.Type, mset *types.MethodSet) llvm.Value {
375+
func (b Builder) abiUncommonType(t types.Type, mset *types.MethodSet) (llvm.Value, int) {
376376
prog := b.Prog
377377
ft := prog.rtType("uncommonType")
378378
var fields []llvm.Value
@@ -389,7 +389,7 @@ func (b Builder) abiUncommonType(t types.Type, mset *types.MethodSet) llvm.Value
389389
fields = append(fields, prog.IntVal(uint64(mcount), prog.Uint16()).impl)
390390
fields = append(fields, prog.IntVal(uint64(xcount), prog.Uint16()).impl)
391391
fields = append(fields, prog.IntVal(moff, prog.Uint32()).impl)
392-
return llvm.ConstNamedStruct(ft.ll, fields)
392+
return llvm.ConstNamedStruct(ft.ll, fields), xcount
393393
}
394394

395395
/*
@@ -401,15 +401,21 @@ type Method struct {
401401
}
402402
*/
403403

404-
func (b Builder) abiUncommonMethods(t types.Type, mset *types.MethodSet) llvm.Value {
404+
func (b Builder) abiUncommonMethods(t types.Type, name string, mset *types.MethodSet) llvm.Value {
405405
prog := b.Prog
406406
ft := prog.rtType("Method")
407407
n := mset.Len()
408408
fields := make([]llvm.Value, n)
409409
pkg, pkgPath := b.abiUncommonPkg(t)
410410
anonymous := pkg == nil
411411
if anonymous {
412-
pkg = types.NewPackage(b.Pkg.Path(), "")
412+
pkgPath := b.Pkg.Path()
413+
if prog.abiTypePruning {
414+
if sym, ok := prog.abiSymbol[name]; ok {
415+
pkgPath = sym.pkgPath
416+
}
417+
}
418+
pkg = types.NewPackage(pkgPath, "")
413419
}
414420
var mPkg *types.Package
415421
for i := 0; i < n; i++ {
@@ -427,18 +433,21 @@ func (b Builder) abiUncommonMethods(t types.Type, mset *types.MethodSet) llvm.Va
427433
name = b.Str(abi.FullName(mPkg, mName)).impl
428434
skipfn = PathOf(mPkg) != pkgPath
429435
}
436+
if prog.abiTypePruning {
437+
skipfn = !prog.methodIsInvoke(m)
438+
}
430439
mSig := m.Type().(*types.Signature)
431440
var tfn, ifn llvm.Value
432441
if skipfn {
433442
tfn = prog.Nil(prog.VoidPtr()).impl
434443
ifn = tfn
435444
} else {
436-
tfn = b.abiMethodFunc(anonymous, mPkg, mName, mSig)
445+
tfn = b.abiMethodFunc(anonymous, pkg, mPkg, mName, mSig)
437446
ifn = tfn
438447
if _, ok := m.Recv().Underlying().(*types.Pointer); !ok {
439448
pRecv := types.NewVar(token.NoPos, mPkg, "", types.NewPointer(mSig.Recv().Type()))
440449
pSig := types.NewSignature(pRecv, mSig.Params(), mSig.Results(), mSig.Variadic())
441-
ifn = b.abiMethodFunc(anonymous, mPkg, mName, pSig)
450+
ifn = b.abiMethodFunc(anonymous, pkg, mPkg, mName, pSig)
442451
}
443452
}
444453
var values []llvm.Value
@@ -458,10 +467,10 @@ func funcType(prog Program, typ types.Type) types.Type {
458467
return ftyp.raw.Type.(*types.Struct).Field(0).Type()
459468
}
460469

461-
func (b Builder) abiMethodFunc(anonymous bool, mPkg *types.Package, mName string, mSig *types.Signature) (tfn llvm.Value) {
470+
func (b Builder) abiMethodFunc(anonymous bool, pkg, mPkg *types.Package, mName string, mSig *types.Signature) (tfn llvm.Value) {
462471
var fullName string
463472
if anonymous {
464-
fullName = b.Pkg.Path() + "." + mSig.Recv().Type().String() + "." + mName
473+
fullName = pkg.Path() + "." + mSig.Recv().Type().String() + "." + mName
465474
} else {
466475
fullName = FuncName(mPkg, mName, mSig.Recv(), false)
467476
}
@@ -484,14 +493,31 @@ func (b Builder) abiMethodFunc(anonymous bool, mPkg *types.Package, mName string
484493
}
485494
*/
486495
func (b Builder) abiType(t types.Type) Expr {
487-
name, _ := b.Pkg.abi.TypeName(t)
488-
g := b.Pkg.VarOf(name)
489496
prog := b.Prog
497+
var name string
498+
if v, ok := prog.abiTypeName[t]; ok {
499+
name = v
500+
} else {
501+
name, _ = b.Pkg.abi.TypeName(t)
502+
}
503+
g := b.Pkg.VarOf(name)
490504
pkg := b.Pkg
491505
if g == nil {
506+
raw := t
492507
if prog.patchType != nil {
493508
t = prog.patchType(t)
494509
}
510+
prog.abiTypeName[raw] = name
511+
if prog.abiTypePruning {
512+
if sym, ok := prog.abiSymbol[name]; ok {
513+
pkgPath := pkg.abi.Pkg
514+
pkg.abi.Pkg = sym.pkgPath
515+
defer func() {
516+
pkg.abi.Pkg = pkgPath
517+
}()
518+
}
519+
}
520+
495521
mset, hasUncommon := b.abiUncommonMethodSet(t)
496522
rt := prog.rtNamed(pkg.abi.RuntimeName(t))
497523
var typ types.Type = rt
@@ -512,24 +538,38 @@ func (b Builder) abiType(t types.Type) Expr {
512538
llvm.ConstNamedStruct(prog.AbiType().ll, fields),
513539
}, exts...)
514540
}
541+
var xcount int
515542
if hasUncommon {
543+
commonTyp := llvm.ConstNamedStruct(prog.Type(rt, InGo).ll, fields)
544+
var uncommonTyp llvm.Value
545+
uncommonTyp, xcount = b.abiUncommonType(t, mset)
546+
uncommonMethods := b.abiUncommonMethods(t, name, mset)
516547
fields = []llvm.Value{
517-
llvm.ConstNamedStruct(prog.Type(rt, InGo).ll, fields),
518-
b.abiUncommonType(t, mset),
519-
b.abiUncommonMethods(t, mset),
548+
commonTyp,
549+
uncommonTyp,
550+
uncommonMethods,
520551
}
521552
}
522553
g.impl.SetInitializer(prog.ctx.ConstStruct(fields, false))
523554
g.impl.SetGlobalConstant(true)
524-
g.impl.SetLinkage(llvm.WeakODRLinkage)
525-
prog.abiSymbol[name] = g.Type
555+
if !prog.abiTypePruning {
556+
g.impl.SetLinkage(llvm.WeakODRLinkage)
557+
prog.abiSymbol[name] = &AbiSymbol{raw: raw, typ: g.Type, pkgPath: pkg.Path(), xcount: xcount}
558+
}
526559
}
527560
return Expr{llvm.ConstGEP(g.impl.GlobalValueType(), g.impl, []llvm.Value{
528561
llvm.ConstInt(prog.Int32().ll, 0, false),
529562
llvm.ConstInt(prog.Int32().ll, 0, false),
530563
}), prog.AbiTypePtr()}
531564
}
532565

566+
type AbiSymbol struct {
567+
raw types.Type
568+
typ Type
569+
pkgPath string
570+
xcount int
571+
}
572+
533573
func (p Package) getAbiTypes(name string) Expr {
534574
prog := p.Prog
535575
names := make([]string, len(prog.abiSymbol))
@@ -541,7 +581,7 @@ func (p Package) getAbiTypes(name string) Expr {
541581
sort.Strings(names)
542582
fields := make([]llvm.Value, len(names))
543583
for i, name := range names {
544-
g := p.doNewVar(name, prog.abiSymbol[name])
584+
g := p.doNewVar(name, prog.abiSymbol[name].typ)
545585
g.impl.SetLinkage(llvm.ExternalLinkage)
546586
g.impl.SetGlobalConstant(true)
547587
ptr := Expr{llvm.ConstGEP(g.impl.GlobalValueType(), g.impl, []llvm.Value{
@@ -581,4 +621,39 @@ func (p Package) InitAbiTypes(fname string) Function {
581621
return initFn
582622
}
583623

624+
func (p Package) PruneAbiTypes(methodIsInvoke func(method *types.Selection) bool) {
625+
prog := p.Prog
626+
var names []string
627+
for k, sym := range prog.abiSymbol {
628+
if sym.xcount == 0 {
629+
continue
630+
}
631+
names = append(names, k)
632+
}
633+
sort.Strings(names)
634+
p.SetResolveLinkname(prog.resolveLinkname)
635+
if methodIsInvoke == nil {
636+
methodIsInvoke = func(method *types.Selection) bool {
637+
if ms, ok := prog.invokeMethods[method.Obj().Name()]; ok {
638+
for m := range ms {
639+
if types.Identical(m, method.Type()) {
640+
return true
641+
}
642+
}
643+
}
644+
return false
645+
}
646+
}
647+
prog.abiTypePruning = true
648+
defer func() {
649+
prog.abiTypePruning = false
650+
}()
651+
prog.methodIsInvoke = methodIsInvoke
652+
b := (&aFunction{Pkg: p, Prog: prog}).NewBuilder()
653+
for _, name := range names {
654+
sym := prog.abiSymbol[name]
655+
b.abiType(sym.raw)
656+
}
657+
}
658+
584659
// -----------------------------------------------------------------------------

ssa/package.go

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go/types"
2323
"runtime"
2424
"strconv"
25+
"strings"
2526
"unsafe"
2627

2728
"github.com/goplus/llgo/internal/env"
@@ -210,15 +211,32 @@ type aProgram struct {
210211

211212
printfTy *types.Signature
212213

213-
paramObjPtr_ *types.Var
214-
linkname map[string]string // pkgPath.nameInPkg => linkname
215-
abiSymbol map[string]Type // abi symbol name => Type
214+
paramObjPtr_ *types.Var
215+
linkname map[string]string // pkgPath.nameInPkg => linkname
216+
abiSymbol map[string]*AbiSymbol // abi symbol name => Type
217+
abiTypeName map[types.Type]string
218+
abiTypePruning bool
219+
methodIsInvoke func(method *types.Selection) bool
220+
221+
invokeMethods map[string]map[types.Type]none
216222

217223
ptrSize int
218224

219225
is32Bits bool
220226
}
221227

228+
type none struct{}
229+
230+
func (p Program) AddInvoke(fn *types.Func) {
231+
name := fn.Name()
232+
m, ok := p.invokeMethods[name]
233+
if !ok {
234+
m = make(map[types.Type]none)
235+
p.invokeMethods[name] = m
236+
}
237+
m[p.patch(fn.Type())] = none{}
238+
}
239+
222240
// A Program presents a program.
223241
type Program = *aProgram
224242

@@ -263,7 +281,8 @@ func NewProgram(target *Target) Program {
263281
ctx: ctx, gocvt: newGoTypes(),
264282
target: target, td: td, is32Bits: is32Bits,
265283
ptrSize: td.PointerSize(), named: make(map[string]Type), fnnamed: make(map[string]int),
266-
linkname: make(map[string]string), abiSymbol: make(map[string]Type),
284+
linkname: make(map[string]string), abiSymbol: make(map[string]*AbiSymbol),
285+
abiTypeName: make(map[types.Type]string), invokeMethods: make(map[string]map[types.Type]none),
267286
}
268287
}
269288

@@ -279,6 +298,10 @@ func (p Program) SetPatch(patchType func(types.Type) types.Type) {
279298
p.patchType = patchType
280299
}
281300

301+
func (p Program) PatchType(typ types.Type) types.Type {
302+
return p.patch(typ)
303+
}
304+
282305
func (p Program) patch(typ types.Type) types.Type {
283306
if p.patchType != nil {
284307
return p.patchType(typ)
@@ -314,6 +337,17 @@ func (p Program) Linkname(name string) (link string, ok bool) {
314337
return
315338
}
316339

340+
func (p Program) resolveLinkname(name string) string {
341+
if link, ok := p.linkname[name]; ok {
342+
prefix, ltarget, _ := strings.Cut(link, ".")
343+
if prefix != "C" {
344+
panic("resolveLinkname: invalid link: " + link)
345+
}
346+
return ltarget
347+
}
348+
return name
349+
}
350+
317351
func (p Program) runtime() *types.Package {
318352
if p.rt == nil {
319353
p.rt = p.rtget()

0 commit comments

Comments
 (0)