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
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 is one step towards removing unnecessary special casts in most
cases. It is also part of removing as much magic as possible from the
compiler (the pragma is explicit, the special name is not).
This has the benefit of not requiring a 'runtime' IR file, so that
complete relocatable files can be built without requiring input IR.
This makes the compiler a lot easier to use without the Makefile.
Code size is not affected.
TODO: do better at it by tracking min/max values of integers. The
following straightforward code doesn't have its bounds checks removed:
for _, n := range slice {
println(n)
}
Instead of mostly heuristics, actually execute the init() instruction in
an interpreter to calculate initializers for globals. This is far more
flexible and extensible, and gives the option of extending the
interpreter to other code and make it a partial evaluator.
This should make it much easier (in the future) to use the standard
library when unused functions contain unimplemented features. But more
importantly, it makes later passes better and makes compiling faster by
not having to scan dead code.
Previously, mostly the types from the ssa package were used directly
with the types from analysis.go as an overlay. This commit uses these
types everywhere and renames a few things here and there to make things
clearer.