Hello, I want to compile Kotlin code to C++ code (...
# compiler
l
Hello, I want to compile Kotlin code to C++ code (not to machine code directly, also don't need a full-blown GC), so I can enjoy programming microcontrollers (like AVR/ATMega on Arduinos) without writing awful code. What paths do you suggest to approach such a project? Interested in seeing different approaches. Parsing Kotlin code myself (using Kotlin code of course) is an option, though I'm wondering if there's any better ways, including using backend IR 🤔.
y
Your best bet probably is to use IR then. I'd suggest maybe at first just to test things out maybe use an
IrGenerationExtension
and just literally transform the code into a string of C++ code and print that out to the console so that you can easily play with it
but I think after that if you want it to be a full-blown backend you need to delve a bit deeper into how Kotlin to LLVM is implemented
That is such an ambitious project though so good luck with figuring out all the rough edges!
s
I think it is going to be hard to get Kotlin work without GC behind the scenes. The language is created in a way that assumes automated garbage collection in many cases, and doesn't really give you that much of direct control of the the memory. I have some random ideas about this, but as Youssef mentioned above, you'll probably have to take native backend and modify it quite significantly :) I would recommend to look into Rust instead lol, but I know you are quite a Kotlin enthusiast, and nothing is impossible with enough determination 🙃
👍 2
Also maybe it is possible to use Kotlin GC and modify it for your use case? I know there's a concept of "not owned" memory in it, so maybe starting from there is a good idea. I am not sure of the constraints of the platform you are targeting, but maybe it'll fit the GC as well
l
Diving into Rust is definitely in my plans, but it doesn't compile to AVR (8bit "CPUs") either. I find Kotlin a bit more approachable, so I think it'd be nice to have it as an option for a platform supposed to be beginner friendly (I'm referring to Arduino). Rust already works for the embedded friendly ARM CPUs BTW, I'll probably get some hardware once I'm more familiar with the options that can work with Rust to make an informed choice.
There's like zero Arduino programs that deal with memory management because they're not allocating objects on each loop run (unneeded). I could just do the same for Kotlin code in this context. My goal is not to have Kotlin compile to C++ no matter what: just to have it output typical Arduino code, without the pain of C++ syntax.
So,
IrGenerationExtension
is the class to look for? I guess I can find it in the API for compiler plugins? I'm wondering how I should get started, if there's any example project, or some info to get setup and figure it out with the right APIs.
r
s
If Rust doesn't compile to AVR, not sure Kotlin can either (just because they both use LLVM), but for exploration, you can even try to write your own backend for it 😄 I think
IrGenerationExtension
is more about adding stuff to IR. You probably want to compile the library, take IR and use it for assembly/source generation. For this, I would recommend looking into how Kotlin creates KLIBs: https://github.com/JetBrains/kotlin/blob/master/kotlin-native/backend.native/compi[…]ackend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt (this one from native) After that you can check the phases the compiler goes through to create LLVM representation, probably you need like one of those: https://github.com/JetBrains/kotlin/blob/master/kotlin-native/backend.native/compi[…]native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt
👍 1
l
Oh, AVR support for Rust is built-in since last July! Nice! Thanks for the info @rocketraman
h
I could also suggest that you write the device driver interfaces as native C++ libraries and then use native kotlin to call them.
l
@Hyugga This currently doesn't work because AVR is not among Kotlin/Native current targets.
m
AVR is not among Kotlin/Native current targets
And never will - minimal requirements are 32-bit CPU and at least 300KB memory.
l
@msink If C++ can do it, Kotlin can too. 32 bit operations can be run (with more CPU cycles) on 8-bit CPUs, just like you can do operations on 64bit primitives like
Long
and
Double
on 32-bit CPUs. I'm not saying everything made in Kotlin should run on AVR. Just that it should be possible to use Kotlin syntax to generate AVR compatible code.
m
No, Kotlin is designed as much more friendly for programmer, but as cost requires much more from device it run on. If you want to programm deeply embedded devices - use plain C, or maybe Rust as more modern analog. (I know - it's my main job for 30 years)
l
@msink Many operations can be optimized at compile time such that they don't require more resources than writing it in C++. For example,
repeat(x) { … }
could be unwrapped to a simple
while
or
for
loop in C++. Function calls can be mapped directly. Arithmetic, it's no different. Of course, the kind of errors, if any would be different that typical Kotlin code, but you can design your Kotlin program so that it can translate properly to C++. You probably have a different point of view with 30 years of C++, it's likely easier for you to use it directly, I understand that, but that won't stop me from trying to make a Kotlin to C++ translator/compiler, even if it doesn't support all of what Kotlin can offer.
m
Well, 30 years if C, not C++ 🙂 And first 10 were asm. Actually there was attempt to port Kotlin to microcontrollers - #embedded-kotlin -unsuccessful. It can be found in Kotlin source code as (long abandoned but not removed) zephyr target. Only kotlin-stdlib required about 150-200KBytes, and performance was very poor.
l
Yep, I knew about the Zephyr target. I think it's possible to make an stdlib-less version where usage of stuff that requires Kotlin classes like List/collections is prohibited (Array could be the only one to work). A successful attempt is a matter of inlining, bringing intrinsics for constructs that can be optimized, eliminating dead code, and shortening symbols names.
@msink When you added zephyr support to Kotlin/Native, was Kotlin already relying on IR, or did it go straight from Kotlin code to LLVM bitcode?
m
AFAIK Kotlin/Native was IR-based from the very beginning. Actually initial version of Kotlin IR was written by Kotlin/Native team, and later adopted to other backends. LLVM IR initially was in .klib, but now even .klib's use Kotlin IR.
l
Linking another thread on that same topic where I got kinda encouraging responses from Svyatoslav Scherbina: https://kotlinlang.slack.com/archives/C3SGXARS6/p1618263156160000 Now that I know it's possible to a certain extent, I'm looking for folks that might be interested in joining forces 🙂 I think I'll try my luck into #embedded-kotlin
110 Views