aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2018-12-09 18:10:04 +0100
committerAyke van Laethem <[email protected]>2018-12-09 18:47:39 +0100
commit564b1b3312b02a0b664b3cf55320236e1227bd82 (patch)
tree0c5a65583cb8e510244250d4fb026480e6d958ef /ir
parent3fec22e819206f1748a010705304beb8c8b47af4 (diff)
downloadtinygo-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.go41
-rw-r--r--ir/passes.go88
2 files changed, 22 insertions, 107 deletions
diff --git a/ir/ir.go b/ir/ir.go
index 5da2e4807..d0028610c 100644
--- a/ir/ir.go
+++ b/ir/ir.go
@@ -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
-}