mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-16 02:33:28 +00:00
compiler: lower interfaces in a separate pass
This commit changes many things:
* Most interface-related operations are moved into an optimization
pass for more modularity. IR construction creates pseudo-calls which
are lowered in this pass.
* Type codes are assigned in this interface lowering pass, after DCE.
* Type codes are sorted by usage: types more often used in type
asserts are assigned lower numbers to ease jump table construction
during machine code generation.
* Interface assertions are optimized: they are replaced by constant
false, comparison against a constant, or a typeswitch with only
concrete types in the general case.
* Interface calls are replaced with unreachable, direct calls, or a
concrete type switch with direct calls depending on the number of
implementing types. This hopefully makes some interface patterns
zero-cost.
These changes lead to a ~0.5K reduction in code size on Cortex-M for
testdata/interface.go. It appears that a major cause for this is the
replacement of function pointers with direct calls, which are far more
susceptible to optimization. Also, not having a fixed global array of
function pointers greatly helps dead code elimination.
This change also makes future optimizations easier, like optimizations
on interface value comparisons.
This commit is contained in:
@@ -19,21 +19,18 @@ import (
|
||||
// View on all functions, types, and globals in a program, with analysis
|
||||
// results.
|
||||
type Program struct {
|
||||
Program *ssa.Program
|
||||
mainPkg *ssa.Package
|
||||
Functions []*Function
|
||||
functionMap map[*ssa.Function]*Function
|
||||
Globals []*Global
|
||||
globalMap map[*ssa.Global]*Global
|
||||
comments map[string]*ast.CommentGroup
|
||||
NamedTypes []*NamedType
|
||||
needsScheduler bool
|
||||
goCalls []*ssa.Go
|
||||
typesWithMethods map[string]*TypeWithMethods // see AnalyseInterfaceConversions
|
||||
typesWithoutMethods map[string]int // see AnalyseInterfaceConversions
|
||||
methodSignatureNames map[string]int // see MethodNum
|
||||
interfaces map[string]*Interface // see AnalyseInterfaceConversions
|
||||
fpWithContext map[string]struct{} // see AnalyseFunctionPointers
|
||||
Program *ssa.Program
|
||||
mainPkg *ssa.Package
|
||||
Functions []*Function
|
||||
functionMap map[*ssa.Function]*Function
|
||||
Globals []*Global
|
||||
globalMap map[*ssa.Global]*Global
|
||||
comments map[string]*ast.CommentGroup
|
||||
NamedTypes []*NamedType
|
||||
needsScheduler bool
|
||||
goCalls []*ssa.Go
|
||||
typesInInterfaces map[string]struct{} // see AnalyseInterfaceConversions
|
||||
fpWithContext map[string]struct{} // see AnalyseFunctionPointers
|
||||
}
|
||||
|
||||
// Function or method.
|
||||
@@ -179,13 +176,11 @@ func NewProgram(lprogram *loader.Program, mainPath string) *Program {
|
||||
}
|
||||
|
||||
p := &Program{
|
||||
Program: program,
|
||||
mainPkg: mainPkg,
|
||||
functionMap: make(map[*ssa.Function]*Function),
|
||||
globalMap: make(map[*ssa.Global]*Global),
|
||||
methodSignatureNames: make(map[string]int),
|
||||
interfaces: make(map[string]*Interface),
|
||||
comments: comments,
|
||||
Program: program,
|
||||
mainPkg: mainPkg,
|
||||
functionMap: make(map[*ssa.Function]*Function),
|
||||
globalMap: make(map[*ssa.Global]*Global),
|
||||
comments: comments,
|
||||
}
|
||||
|
||||
for _, pkg := range packageList {
|
||||
@@ -270,18 +265,6 @@ func (p *Program) GetGlobal(ssaGlobal *ssa.Global) *Global {
|
||||
return p.globalMap[ssaGlobal]
|
||||
}
|
||||
|
||||
// SortMethods sorts the list of methods by method ID.
|
||||
func (p *Program) SortMethods(methods []*types.Selection) {
|
||||
m := &methodList{methods: methods, program: p}
|
||||
sort.Sort(m)
|
||||
}
|
||||
|
||||
// SortFuncs sorts the list of functions by method ID.
|
||||
func (p *Program) SortFuncs(funcs []*types.Func) {
|
||||
m := &funcList{funcs: funcs, program: p}
|
||||
sort.Sort(m)
|
||||
}
|
||||
|
||||
func (p *Program) MainPkg() *ssa.Package {
|
||||
return p.mainPkg
|
||||
}
|
||||
@@ -442,46 +425,6 @@ func (p *Program) IsVolatile(t types.Type) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper type to implement sort.Interface for []*types.Selection.
|
||||
type methodList struct {
|
||||
methods []*types.Selection
|
||||
program *Program
|
||||
}
|
||||
|
||||
func (m *methodList) Len() int {
|
||||
return len(m.methods)
|
||||
}
|
||||
|
||||
func (m *methodList) Less(i, j int) bool {
|
||||
iid := m.program.MethodNum(m.methods[i].Obj().(*types.Func))
|
||||
jid := m.program.MethodNum(m.methods[j].Obj().(*types.Func))
|
||||
return iid < jid
|
||||
}
|
||||
|
||||
func (m *methodList) Swap(i, j int) {
|
||||
m.methods[i], m.methods[j] = m.methods[j], m.methods[i]
|
||||
}
|
||||
|
||||
// Wrapper type to implement sort.Interface for []*types.Func.
|
||||
type funcList struct {
|
||||
funcs []*types.Func
|
||||
program *Program
|
||||
}
|
||||
|
||||
func (fl *funcList) Len() int {
|
||||
return len(fl.funcs)
|
||||
}
|
||||
|
||||
func (fl *funcList) Less(i, j int) bool {
|
||||
iid := fl.program.MethodNum(fl.funcs[i])
|
||||
jid := fl.program.MethodNum(fl.funcs[j])
|
||||
return iid < jid
|
||||
}
|
||||
|
||||
func (fl *funcList) Swap(i, j int) {
|
||||
fl.funcs[i], fl.funcs[j] = fl.funcs[j], fl.funcs[i]
|
||||
}
|
||||
|
||||
// Return true if this is a CGo-internal function that can be ignored.
|
||||
func isCGoInternal(name string) bool {
|
||||
if strings.HasPrefix(name, "_Cgo_") || strings.HasPrefix(name, "_cgo") {
|
||||
|
||||
Reference in New Issue
Block a user