mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-12 15:03:41 +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:
+33
-41
@@ -43,29 +43,30 @@ type Config struct {
|
||||
|
||||
type Compiler struct {
|
||||
Config
|
||||
mod llvm.Module
|
||||
ctx llvm.Context
|
||||
builder llvm.Builder
|
||||
dibuilder *llvm.DIBuilder
|
||||
cu llvm.Metadata
|
||||
difiles map[string]llvm.Metadata
|
||||
ditypes map[string]llvm.Metadata
|
||||
machine llvm.TargetMachine
|
||||
targetData llvm.TargetData
|
||||
intType llvm.Type
|
||||
i8ptrType llvm.Type // for convenience
|
||||
uintptrType llvm.Type
|
||||
coroIdFunc llvm.Value
|
||||
coroSizeFunc llvm.Value
|
||||
coroBeginFunc llvm.Value
|
||||
coroSuspendFunc llvm.Value
|
||||
coroEndFunc llvm.Value
|
||||
coroFreeFunc llvm.Value
|
||||
initFuncs []llvm.Value
|
||||
deferFuncs []*ir.Function
|
||||
deferInvokeFuncs []InvokeDeferFunction
|
||||
ctxDeferFuncs []ContextDeferFunction
|
||||
ir *ir.Program
|
||||
mod llvm.Module
|
||||
ctx llvm.Context
|
||||
builder llvm.Builder
|
||||
dibuilder *llvm.DIBuilder
|
||||
cu llvm.Metadata
|
||||
difiles map[string]llvm.Metadata
|
||||
ditypes map[string]llvm.Metadata
|
||||
machine llvm.TargetMachine
|
||||
targetData llvm.TargetData
|
||||
intType llvm.Type
|
||||
i8ptrType llvm.Type // for convenience
|
||||
uintptrType llvm.Type
|
||||
coroIdFunc llvm.Value
|
||||
coroSizeFunc llvm.Value
|
||||
coroBeginFunc llvm.Value
|
||||
coroSuspendFunc llvm.Value
|
||||
coroEndFunc llvm.Value
|
||||
coroFreeFunc llvm.Value
|
||||
initFuncs []llvm.Value
|
||||
deferFuncs []*ir.Function
|
||||
deferInvokeFuncs []InvokeDeferFunction
|
||||
ctxDeferFuncs []ContextDeferFunction
|
||||
interfaceInvokeWrappers []interfaceInvokeWrapper
|
||||
ir *ir.Program
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
@@ -489,6 +490,15 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||
c.builder.CreateRetVoid()
|
||||
}
|
||||
|
||||
// Define the already declared functions that wrap methods for use in
|
||||
// interfaces.
|
||||
for _, state := range c.interfaceInvokeWrappers {
|
||||
err = c.createInterfaceInvokeWrapper(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// After all packages are imported, add a synthetic initializer function
|
||||
// that calls the initializer of each package.
|
||||
initFn := c.ir.GetFunction(c.ir.Program.ImportedPackage("runtime").Members["initAll"].(*ssa.Function))
|
||||
@@ -534,13 +544,6 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||
}
|
||||
c.builder.CreateRetVoid()
|
||||
|
||||
// Add runtime type information for interfaces: interface calls and type
|
||||
// asserts.
|
||||
err = c.createInterfaceRTTI()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// see: https://reviews.llvm.org/D18355
|
||||
c.mod.AddNamedMetadataOperand("llvm.module.flags",
|
||||
c.ctx.MDNode([]llvm.Metadata{
|
||||
@@ -995,17 +998,6 @@ func (c *Compiler) getInterpretedValue(prefix string, value ir.Value) (llvm.Valu
|
||||
ptr := llvm.ConstInBoundsGEP(value.Global.LLVMGlobal, []llvm.Value{zero})
|
||||
return ptr, nil
|
||||
|
||||
case *ir.InterfaceValue:
|
||||
underlying := llvm.ConstPointerNull(c.i8ptrType) // could be any 0 value
|
||||
if value.Elem != nil {
|
||||
elem, err := c.getInterpretedValue(prefix, value.Elem)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
underlying = elem
|
||||
}
|
||||
return c.parseMakeInterface(underlying, value.Type, prefix)
|
||||
|
||||
case *ir.MapValue:
|
||||
// Create initial bucket.
|
||||
firstBucketGlobal, keySize, valueSize, err := c.initMapNewBucket(prefix, value.Type)
|
||||
|
||||
Reference in New Issue
Block a user