diff options
author | Ayke van Laethem <[email protected]> | 2018-12-09 18:10:04 +0100 |
---|---|---|
committer | Ayke van Laethem <[email protected]> | 2018-12-09 18:47:39 +0100 |
commit | 564b1b3312b02a0b664b3cf55320236e1227bd82 (patch) | |
tree | 0c5a65583cb8e510244250d4fb026480e6d958ef /ir | |
parent | 3fec22e819206f1748a010705304beb8c8b47af4 (diff) | |
download | tinygo-564b1b3312b02a0b664b3cf55320236e1227bd82.tar.gz tinygo-564b1b3312b02a0b664b3cf55320236e1227bd82.zip |
compiler: always use fat function pointers with context
This reduces complexity in the compiler without affecting binary sizes
too much.
Cortex-M0: no changes
Linux x64: no changes
WebAssembly: some testcases (calls, coroutines, map) are slightly bigger
Diffstat (limited to 'ir')
-rw-r--r-- | ir/ir.go | 41 | ||||
-rw-r--r-- | ir/passes.go | 88 |
2 files changed, 22 insertions, 107 deletions
@@ -19,33 +19,30 @@ 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 - typesInInterfaces map[string]struct{} // 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 } // Function or method. type Function struct { *ssa.Function - LLVMFn llvm.Value - linkName string // go:linkname, go:export, go:interrupt - exported bool // go:export - nobounds bool // go:nobounds - blocking bool // calculated by AnalyseBlockingRecursive - flag bool // used by dead code elimination - interrupt bool // go:interrupt - addressTaken bool // used as function pointer, calculated by AnalyseFunctionPointers - parents []*Function // calculated by AnalyseCallgraph - children []*Function // calculated by AnalyseCallgraph + LLVMFn llvm.Value + linkName string // go:linkname, go:export, go:interrupt + exported bool // go:export + nobounds bool // go:nobounds + blocking bool // calculated by AnalyseBlockingRecursive + flag bool // used by dead code elimination + interrupt bool // go:interrupt + parents []*Function // calculated by AnalyseCallgraph + children []*Function // calculated by AnalyseCallgraph } // Global variable, possibly constant. diff --git a/ir/passes.go b/ir/passes.go index e2dbbb88b..792700b75 100644 --- a/ir/passes.go +++ b/ir/passes.go @@ -17,16 +17,15 @@ import ( // String() string // Read([]byte) (int, error) func MethodSignature(method *types.Func) string { - return method.Name() + Signature(method.Type().(*types.Signature)) + return method.Name() + signature(method.Type().(*types.Signature)) } -// Make a readable version of a function (pointer) signature. This string is -// used internally to match signatures (like in AnalyseFunctionPointers). +// Make a readable version of a function (pointer) signature. // Examples: // // () string // (string, int) (int, error) -func Signature(sig *types.Signature) string { +func signature(sig *types.Signature) string { s := "" if sig.Params().Len() == 0 { s += "()" @@ -101,69 +100,6 @@ func (p *Program) AnalyseCallgraph() { } } -// Find all types that are put in an interface. -func (p *Program) AnalyseInterfaceConversions() { - // Clear, if AnalyseInterfaceConversions has been called before. - p.typesInInterfaces = map[string]struct{}{} - - for _, f := range p.Functions { - for _, block := range f.Blocks { - for _, instr := range block.Instrs { - switch instr := instr.(type) { - case *ssa.MakeInterface: - name := instr.X.Type().String() - if _, ok := p.typesInInterfaces[name]; !ok { - p.typesInInterfaces[name] = struct{}{} - } - } - } - } - } -} - -// Analyse which function pointer signatures need a context parameter. -// This makes calling function pointers more efficient. -func (p *Program) AnalyseFunctionPointers() { - // Clear, if AnalyseFunctionPointers has been called before. - p.fpWithContext = map[string]struct{}{} - - for _, f := range p.Functions { - for _, block := range f.Blocks { - for _, instr := range block.Instrs { - switch instr := instr.(type) { - case ssa.CallInstruction: - for _, arg := range instr.Common().Args { - switch arg := arg.(type) { - case *ssa.Function: - f := p.GetFunction(arg) - f.addressTaken = true - } - } - case *ssa.DebugRef: - default: - // For anything that isn't a call... - for _, operand := range instr.Operands(nil) { - if operand == nil || *operand == nil || isCGoInternal((*operand).Name()) { - continue - } - switch operand := (*operand).(type) { - case *ssa.Function: - f := p.GetFunction(operand) - f.addressTaken = true - } - } - } - switch instr := instr.(type) { - case *ssa.MakeClosure: - fn := instr.Fn.(*ssa.Function) - sig := Signature(fn.Signature) - p.fpWithContext[sig] = struct{}{} - } - } - } - } -} - // Analyse which functions are recursively blocking. // // Depends on AnalyseCallgraph. @@ -321,21 +257,3 @@ func (p *Program) IsBlocking(f *Function) bool { } return f.blocking } - -func (p *Program) FunctionNeedsContext(f *Function) bool { - if !f.addressTaken { - if f.Signature.Recv() != nil { - _, hasInterfaceConversion := p.typesInInterfaces[f.Signature.Recv().Type().String()] - if hasInterfaceConversion && p.SignatureNeedsContext(f.Signature) { - return true - } - } - return false - } - return p.SignatureNeedsContext(f.Signature) -} - -func (p *Program) SignatureNeedsContext(sig *types.Signature) bool { - _, needsContext := p.fpWithContext[Signature(sig)] - return needsContext -} |