So I was looking at
this slideshow from KotlinConf'2018 about how to write Kotlin compiler plugins, and what surprised me is that a big part of the process is generating JVM bytecode / LLVM IR directly.
I've always assumed that compiler plugins are somewhat like procedural macros with access to all data from the compiler, and that you can operate at multiple levels of abstractions (e.g. modify source code, or modify/generate the ASTs from the compiler frontend, or generate bytecode directly), but this is just a naive guess.
Is this still the case? Or are there now higher level constructs (especially with KMP and K2)? Just curious about this.