aboutsummaryrefslogtreecommitdiffhomepage
path: root/transform/interface-lowering.go
AgeCommit message (Collapse)Author
2023-10-01all: remove LLVM 14 supportAyke van Laethem
This is a big change: apart from removing LLVM 14 it also removes typed pointer support (which was only fully supported in LLVM up to version 14). This removes about 200 lines of code, but more importantly removes a ton of special cases for LLVM 14.
2023-06-09compiler,transform: fix for pointer-to-pointer type switches from @aykevlDamian Gryski
2023-03-02transform: fix non-determinism in the interface lowering passAyke van Laethem
This non-determinism was introduced in https://github.com/tinygo-org/tinygo/pull/2640. Non-determinism in the compiler is a bug because it makes it harder to find whether a compiler change actually affected the binary. Fixes https://github.com/tinygo-org/tinygo/issues/3504
2023-02-17all: refactor reflect packageAyke van Laethem
This is a big commit that changes the way runtime type information is stored in the binary. Instead of compressing it and storing it in a number of sidetables, it is stored similar to how the Go compiler toolchain stores it (but still more compactly). This has a number of advantages: * It is much easier to add new features to reflect support. They can simply be added to these structs without requiring massive changes (especially in the reflect lowering pass). * It removes the reflect lowering pass, which was a large amount of hard to understand and debug code. * The reflect lowering pass also required merging all LLVM IR into one module, which is terrible for performance especially when compiling large amounts of code. See issue 2870 for details. * It is (probably!) easier to reason about for the compiler. The downside is that it increases code size a bit, especially when reflect is involved. I hope to fix some of that in later patches.
2022-10-19ci: add support for LLVM 15Ayke van Laethem
This commit switches to LLVM 15 everywhere by default, while still keeping LLVM 14 support.
2022-10-19all: remove pointer ElementType callsAyke van Laethem
This is needed for opaque pointers, which are enabled by default in LLVM 15.
2022-10-19all: replace llvm.Const* calls with builder.Create* callsAyke van Laethem
A number of llvm.Const* functions (in particular extractvalue and insertvalue) were removed in LLVM 15, so we have to use a builder instead. This builder will create the same constant values, it simply uses a different API.
2022-10-19all: add type parameter to CreateCallAyke van Laethem
This uses LLVMBuildCall2 in the background, which is the replacement for the deprecated LLVMBuildCall function.
2022-05-30builder: free LLVM objects after useAyke van Laethem
This reduces the TinyGo memory consumption when running make tinygo-test from 5.8GB to around 2GB on my laptop.
2022-01-19compiler: remove parentHandle from calling conventionNia Waldvogel
This removes the parentHandle argument from the internal calling convention. It was formerly used to implment coroutines. Now that coroutines have been removed, it is no longer necessary.
2021-11-06transform: add debug info in interface lowering passAyke van Laethem
This is fake debug info. It doesn't point to a source location because there is no source location. However, it helps to correctly attribute code size usage to particular packages. I've also updated builder/sizes.go with some debugging helpers.
2021-11-03compiler: refactor when the optsize attribute is setAyke van Laethem
This commit has a few related changes: * It sets the optsize attribute immediately in the compiler instead of adding it to each function afterwards in a loop. This seems to me like the more appropriate way to do it. * It centralizes setting the optsize attribute in the transform package, to make later changes easier. * It sets the optsize in a few more places: to runtime.initAll and to WebAssembly i64 wrappers. This commit does not affect the binary size of any of the smoke tests, so should be risk-free.
2021-10-31transform (interface): fix merge error from #2202Nia Waldvogel
2021-10-31compiler: simplify interface loweringAyke van Laethem
This commit simplifies the IR a little bit: instead of calling pseudo-functions runtime.interfaceImplements and runtime.interfaceMethod, real declared functions are being called that are then defined in the interface lowering pass. This should simplify the interaction between various transformation passes. It also reduces the number of lines of code, which is generally a good thing.
2021-10-28transform: work around renamed return type after merging LLVM modulesAyke van Laethem
This fix is very similar to https://github.com/tinygo-org/tinygo/pull/1768, but now for the return type. It fixes the issue in https://github.com/tinygo-org/tinygo/issues/1887. Like #1768, I'm not sure how to test this as it is very specific to certain renames that LLVM does and that don't seem very reproducable.
2021-10-26transform: remove some dead codeAyke van Laethem
This showed up in the linter and it makes sense to just remove it.
2021-06-17compiler: refactor method namesAyke van Laethem
This commit includes two changes: * It makes unexported interface methods package-private, so that it's not possible to type-assert on an unexported method in a different package. * It makes the globals used to identify interface methods defined globals, so that they can (eventually) be left in the program for an eventual non-LTO build mode.
2021-05-03transform: split interface and reflect loweringAyke van Laethem
These two passes are related, but can definitely work independently. Which is what this change does: it splits the two passes. This should make it easier to change these two new passes in the future. This change now also enables slightly better testing by testing these two passes independently. In particular, the reflect lowering pass got some actual tests: it was barely unit-tested before. I have verified that this doesn't really change code size, at least not on the microbit target. Two tests do change, but in a very minor way (and in opposite direction).
2021-04-08transform: don't rely on struct name of runtime.typecodeIDAyke van Laethem
Sometimes, LLVM may rename named structs when merging modules. Therefore, we can't rely on typecodeID structs to retain their struct names. This commit changes the interface lowering pass to not rely on these names. The interp package does however still rely on this name, but I hope to fix that in the future.
2021-04-08builder: add optsize attribute while building the packageAyke van Laethem
This simplifies future changes. While the move itself is very simple, it required some other changes to a few transforms that create new functions to add the optsize attribute manually. It also required abstracting away the optimization level flags (based on the -opt flag) so that it can easily be retrieved from the config object. This commit does not impact binary size on baremetal and WebAssembly. I've seen a few tests on linux/amd64 grow slightly in size, but I'm not too worried about those.
2021-04-05transform: fix bug in interface lowering when signatures are renamedAyke van Laethem
In rare cases the signature might change as a result of LLVM renaming some named struct types when multiple LLVM modules are merged. The easiest workaround is to detect such mismatched signatures and adding a bitcast: this should be safe as the underlying data is effectively of the same type.
2021-03-28transform: optimize reflect.Type Implements() methodAyke van Laethem
This commit adds a new transform that converts reflect Implements() calls to runtime.interfaceImplements. At the moment, the Implements() method is not yet implemented (how ironic) but if the value passed to Implements is known at compile time the method call can be optimized to runtime.interfaceImplements to make it a regular interface assert. This commit is the last change necessary to add basic support for the encoding/json package. The json package is certainly not yet fully supported, but some trivial objects can be converted to JSON.
2021-03-23compiler: do not check for impossible type assertsAyke van Laethem
Previously there was code to avoid impossible type asserts but it wasn't great and in fact was too aggressive when combined with reflection. This commit improves this by checking all types that exist in the program that may appear in an interface (even struct fields and the like) but without creating runtime.typecodeID objects with the type assert. This has two advantages: * As mentioned, it optimizes impossible type asserts away. * It allows methods on types that were only asserted on (in runtime.typeAssert) but never used in an interface to be optimized away using GlobalDCE. This may have a cascading effect so that other parts of the code can be further optimized. This sometimes massively improves code size and mostly negates the code size regression of the previous commit.
2021-03-23compiler: merge runtime.typecodeID and runtime.typeInInterfaceAyke van Laethem
This distinction was useful before when reflect wasn't properly supported. Back then it made sense to only include method sets that were actually used in an interface. But now that it is possible to get to other values (for example, by extracting fields from structs) and it is possible to turn them back into interfaces, it is necessary to preserve all method sets that can possibly be used in the program in a type assert, interface assert or interface method call. In the future, this logic will need to be revisited again when reflect.New or reflect.Zero gets implemented. Code size increases a bit in some cases, but usually in a very limited way (except for one outlier in the drivers smoke tests). The next commit will improve the situation significantly.
2021-03-21builder, compiler: compile and cache packages in parallelAyke van Laethem
This commit switches from the previous behavior of compiling the whole program at once, to compiling every package in parallel and linking the LLVM bitcode files together for further whole-program optimization. This is a small performance win, but it has several advantages in the future: - There are many more things that can be done per package in parallel, avoiding the bottleneck at the end of the compiler phase. This should speed up the compiler futher. - This change is a necessary step towards a non-LTO build mode for fast incremental builds that only rebuild the changed package, when compiler speed is more important than binary size. - This change refactors the compiler in such a way that it will be easier to inspect the IR for one package only. Inspecting this IR will be very helpful for compiler developers.
2020-05-28transform: introduce check for method calls on nil interfacesAyke van Laethem
I ran into an issue where I did a method call on a nil interface and it resulted in a HardFault. Luckily I quickly realized what was going on so I could fix it, but I think undefined behavior is definitely the wrong behavior in this case. This commit therefore changes such calls to cause a nil panic instead of introducing undefined behavior. This does have a code size impact. It's relatively minor, much lower than I expected. When comparing the before and after of the drivers smoke tests (probably the most representative sample available), I found that most did not change at all and those that did change, normally not more than 100 bytes (16 or 32 byte changes are typical). Right now the pattern is the following: switch typecode { case 1: call method 1 case 2: call method 2 default: nil panic } I also tried the following (in the hope that it would be easier to optimize), but it didn't really result in a code size reduction: switch typecode { case 1: call method 1 case 2: call method 2 case 0: nil panic default: unreachable } Some code got smaller, while other code (the majority) got bigger. Maybe this can be improved once range[1] is finally allowed[2] on function parameters, but it'll probably take a while before that is implemented. [1]: https://llvm.org/docs/LangRef.html#range-metadata [2]: https://github.com/rust-lang/rust/issues/50156
2020-05-28transform: do not special-case zero or one implementations of a method callAyke van Laethem
This is a common case, but it also complicates the code. Removing this special case does have a negative effect on code size in rare cases, but I don't think it's worth keeping around (and possibly causing bugs) for such uncommon cases. This should not result in functional changes, although the output (as stated above) sometimes changes a little bit.
2020-03-25transform: fix error in interface lowering passAyke van Laethem
It appears that LLVM can sometimes recognize that multiple calls to runtime.interfaceMethod can be merged into one. When that happens, the interface lowering pass shows an error as it didn't expect that situation. Luckily the fix is very easy.
2020-03-24transform: replace panics with source locationsAyke van Laethem
Panics are bad for usability: whenever something breaks, the user is shown a (not very informative) backtrace. Replace it with real error messages instead, that even try to display the Go source location.
2019-11-17compiler: add support for async interface callsJaden Weiss
2019-11-15compiler,transform: move interface lowering to transform packageAyke van Laethem