Like most compilers, TinyGo is a compiler built as a pipeline of transformations that each translate an input to a simpler output version (also called lowering). However, most of these part are not in TinyGo itself. The frontend is mostly implemented by external Go libraries, and most optimizations and code generation is implemented by LLVM.

This is roughly the pipeline for TinyGo:

  • Lexing, parsing, and typechecking is done by packages in the standard library and in the golang.org/x/tools/go library.
  • SSA construction (a very important step) is done by the golang.org/x/tools/go/ssa package.
  • The Go SSA is then transformed into LLVM IR by the compiler package. Both forms are SSA, but because Go SSA is higher level and contains Go-specific constructs (like interfaces and goroutines) this is non-trivial. However, the vast majority of the work is simply lowering the available Go SSA into LLVM IR, possibly calling some runtime library intrinsics in the process (for example, operations on maps).
  • Go does a lot of initialization at runtime, which is really bad for code size. This includes all global variables: they are all initialized at runtime, not at compile time like C. So TinyGo interprets these functions at compile time as far as it is able to.
  • The resulting IR is then first optimized by a mixture of handpicked LLVM optimization passes, TinyGo-specific optimizations (escape analysis, string-to-[]byte optimizations, etc.) and custom lowering. For example, this is the time when interfaces are lowered to their final form to benefit from the optimizations already done until that point.
  • This LLVM IR is then optimized by the LLVM optimizer, which has a large array of standard optimization passes. This is the standard optimization pipeline as is also used by Clang.
  • After all optimizations have run, a few fixups are needed for AVR for globals, because AVR has separate address spaces for flash and RAM. This is implemented by the compiler package.
  • Finally, the resulting machine code is emitted by LLVM to an object file.

This is just the compiler. TinyGo can also automatically link the file and flash it to a device, if needed.