Skip to content

Commit a099b5c

Browse files
committed
ssa: prune abitypes by callgraph
1 parent 6fc281b commit a099b5c

File tree

5 files changed

+256
-25
lines changed

5 files changed

+256
-25
lines changed

cl/instr.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ func (p *context) pkgNoInit(pkg *types.Package) bool {
505505
func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) {
506506
cv := call.Value
507507
if mthd := call.Method; mthd != nil {
508+
p.prog.AddInvoke(mthd)
508509
o := p.compileValue(b, cv)
509510
fn := b.Imethod(o, mthd)
510511
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: 98 additions & 21 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, _ := 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
for i := 0; i < n; i++ {
415421
m := mset.At(i)
@@ -421,12 +427,17 @@ func (b Builder) abiUncommonMethods(t types.Type, mset *types.MethodSet) llvm.Va
421427
}
422428
mSig := m.Type().(*types.Signature)
423429
var tfn, ifn llvm.Value
424-
tfn = b.abiMethodFunc(anonymous, pkg, mName, mSig)
425-
ifn = tfn
426-
if _, ok := m.Recv().Underlying().(*types.Pointer); !ok {
427-
pRecv := types.NewVar(token.NoPos, pkg, "", types.NewPointer(mSig.Recv().Type()))
428-
pSig := types.NewSignature(pRecv, mSig.Params(), mSig.Results(), mSig.Variadic())
429-
ifn = b.abiMethodFunc(anonymous, pkg, mName, pSig)
430+
if prog.abiTypePruning && !prog.methodIsInvoke(m) {
431+
tfn = prog.Nil(prog.VoidPtr()).impl
432+
ifn = tfn
433+
} else {
434+
tfn = b.abiMethodFunc(anonymous, pkg, mName, mSig)
435+
ifn = tfn
436+
if _, ok := m.Recv().Underlying().(*types.Pointer); !ok {
437+
pRecv := types.NewVar(token.NoPos, pkg, "", types.NewPointer(mSig.Recv().Type()))
438+
pSig := types.NewSignature(pRecv, mSig.Params(), mSig.Results(), mSig.Variadic())
439+
ifn = b.abiMethodFunc(anonymous, pkg, mName, pSig)
440+
}
430441
}
431442
var values []llvm.Value
432443
values = append(values, name)
@@ -448,7 +459,7 @@ func funcType(prog Program, typ types.Type) types.Type {
448459
func (b Builder) abiMethodFunc(anonymous bool, mPkg *types.Package, mName string, mSig *types.Signature) (tfn llvm.Value) {
449460
var fullName string
450461
if anonymous {
451-
fullName = b.Pkg.Path() + "." + mSig.Recv().Type().String() + "." + mName
462+
fullName = mPkg.Path() + "." + mSig.Recv().Type().String() + "." + mName
452463
} else {
453464
fullName = FuncName(mPkg, mName, mSig.Recv(), false)
454465
}
@@ -471,14 +482,31 @@ func (b Builder) abiMethodFunc(anonymous bool, mPkg *types.Package, mName string
471482
}
472483
*/
473484
func (b Builder) abiType(t types.Type) Expr {
474-
name, _ := b.Pkg.abi.TypeName(t)
475-
g := b.Pkg.VarOf(name)
476485
prog := b.Prog
486+
var name string
487+
if v, ok := prog.abiTypeName[t]; ok {
488+
name = v
489+
} else {
490+
name, _ = b.Pkg.abi.TypeName(t)
491+
}
492+
g := b.Pkg.VarOf(name)
477493
pkg := b.Pkg
478494
if g == nil {
495+
raw := t
479496
if prog.patchType != nil {
480497
t = prog.patchType(t)
481498
}
499+
prog.abiTypeName[raw] = name
500+
if prog.abiTypePruning {
501+
if sym, ok := prog.abiSymbol[name]; ok {
502+
pkgPath := pkg.abi.Pkg
503+
pkg.abi.Pkg = sym.pkgPath
504+
defer func() {
505+
pkg.abi.Pkg = pkgPath
506+
}()
507+
}
508+
}
509+
482510
mset, hasUncommon := b.abiUncommonMethodSet(t)
483511
rt := prog.rtNamed(pkg.abi.RuntimeName(t))
484512
var typ types.Type = rt
@@ -499,24 +527,38 @@ func (b Builder) abiType(t types.Type) Expr {
499527
llvm.ConstNamedStruct(prog.AbiType().ll, fields),
500528
}, exts...)
501529
}
530+
var xcount int
502531
if hasUncommon {
532+
commonTyp := llvm.ConstNamedStruct(prog.Type(rt, InGo).ll, fields)
533+
var uncommonTyp llvm.Value
534+
uncommonTyp, xcount = b.abiUncommonType(t, mset)
535+
uncommonMethods := b.abiUncommonMethods(t, name, mset)
503536
fields = []llvm.Value{
504-
llvm.ConstNamedStruct(prog.Type(rt, InGo).ll, fields),
505-
b.abiUncommonType(t, mset),
506-
b.abiUncommonMethods(t, mset),
537+
commonTyp,
538+
uncommonTyp,
539+
uncommonMethods,
507540
}
508541
}
509542
g.impl.SetInitializer(prog.ctx.ConstStruct(fields, false))
510543
g.impl.SetGlobalConstant(true)
511-
g.impl.SetLinkage(llvm.WeakODRLinkage)
512-
prog.abiSymbol[name] = g.Type
544+
if !prog.abiTypePruning {
545+
g.impl.SetLinkage(llvm.WeakODRLinkage)
546+
prog.abiSymbol[name] = &AbiSymbol{raw: raw, typ: g.Type, pkgPath: pkg.Path(), xcount: xcount}
547+
}
513548
}
514549
return Expr{llvm.ConstGEP(g.impl.GlobalValueType(), g.impl, []llvm.Value{
515550
llvm.ConstInt(prog.Int32().ll, 0, false),
516551
llvm.ConstInt(prog.Int32().ll, 0, false),
517552
}), prog.AbiTypePtr()}
518553
}
519554

555+
type AbiSymbol struct {
556+
raw types.Type
557+
typ Type
558+
pkgPath string
559+
xcount int
560+
}
561+
520562
func (p Package) getAbiTypes(name string) Expr {
521563
prog := p.Prog
522564
names := make([]string, len(prog.abiSymbol))
@@ -528,7 +570,7 @@ func (p Package) getAbiTypes(name string) Expr {
528570
sort.Strings(names)
529571
fields := make([]llvm.Value, len(names))
530572
for i, name := range names {
531-
g := p.doNewVar(name, prog.abiSymbol[name])
573+
g := p.doNewVar(name, prog.abiSymbol[name].typ)
532574
g.impl.SetLinkage(llvm.ExternalLinkage)
533575
g.impl.SetGlobalConstant(true)
534576
ptr := Expr{llvm.ConstGEP(g.impl.GlobalValueType(), g.impl, []llvm.Value{
@@ -568,4 +610,39 @@ func (p Package) InitAbiTypes(fname string) Function {
568610
return initFn
569611
}
570612

613+
func (p Package) PruneAbiTypes(methodIsInvoke func(method *types.Selection) bool) {
614+
prog := p.Prog
615+
var names []string
616+
for k, sym := range prog.abiSymbol {
617+
if sym.xcount == 0 {
618+
continue
619+
}
620+
names = append(names, k)
621+
}
622+
sort.Strings(names)
623+
p.SetResolveLinkname(prog.resolveLinkname)
624+
if methodIsInvoke == nil {
625+
methodIsInvoke = func(method *types.Selection) bool {
626+
if ms, ok := prog.invokeMethods[method.Obj().Name()]; ok {
627+
for m := range ms {
628+
if types.Identical(m, method.Type()) {
629+
return true
630+
}
631+
}
632+
}
633+
return false
634+
}
635+
}
636+
prog.abiTypePruning = true
637+
defer func() {
638+
prog.abiTypePruning = false
639+
}()
640+
prog.methodIsInvoke = methodIsInvoke
641+
b := (&aFunction{Pkg: p, Prog: prog}).NewBuilder()
642+
for _, name := range names {
643+
sym := prog.abiSymbol[name]
644+
b.abiType(sym.raw)
645+
}
646+
}
647+
571648
// -----------------------------------------------------------------------------

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, tm: tm, 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

@@ -287,6 +306,10 @@ func (p Program) SetPatch(patchType func(types.Type) types.Type) {
287306
p.patchType = patchType
288307
}
289308

309+
func (p Program) PatchType(typ types.Type) types.Type {
310+
return p.patch(typ)
311+
}
312+
290313
func (p Program) patch(typ types.Type) types.Type {
291314
if p.patchType != nil {
292315
return p.patchType(typ)
@@ -322,6 +345,17 @@ func (p Program) Linkname(name string) (link string, ok bool) {
322345
return
323346
}
324347

348+
func (p Program) resolveLinkname(name string) string {
349+
if link, ok := p.linkname[name]; ok {
350+
prefix, ltarget, _ := strings.Cut(link, ".")
351+
if prefix != "C" {
352+
panic("resolveLinkname: invalid link: " + link)
353+
}
354+
return ltarget
355+
}
356+
return name
357+
}
358+
325359
func (p Program) runtime() *types.Package {
326360
if p.rt == nil {
327361
p.rt = p.rtget()

0 commit comments

Comments
 (0)