Sorry, the README was out of date. Those numbers are from the beginning of the year, and now they are:
| .NET Core tests | 1764 | 48 | 20 | 96.29% |
| C Core tests | 1712 | 71 | 8 | 95.59% |
I am not affiliated with `cg_gcc`, but I have contributed some tiny things here and there.
Currently, `cg_gcc` is within spitting distance of being able to bootstrap the compiler. There really are only 3(!) bugs that currently stop a stage 2 build.
I know for sure, because I found workarounds for them, and have a working stage 2 build. A stage 3 build requires a bit more RAM than I have, but, besides that, it is definitely possible.
Those 3 bugs are:
1. Lack of support for 128 bit SwitchInt terminators(Rust IR equivalent of switch). This is likely caused by an issue on the GCC side, since libgccjit rejects 128 bit labels provided by `cg_gcc`.
2. A semantic difference between Rust's `#[inline(always)]` and `__attribute__((always_inline)) `. In Rust `#[inline(always)]` is a hint and works on recursive functions, but the GCC equivalent is not a hint, but a gurante, and does not work on recursive function.
3. `cg_gcc` miscompiles the Rust compiler's interner code if level 3 optimzations are enabled. The Rust compiler interner is quite complex, and does a lot of fiddly unsafe things, so it is the most likely to break. The exact cause of this issue is hard to pin down, but it can be worked around(by setting a lower opt level).
If you work around those issues, `cg_gcc` is able to successfully build the Rust compiler, at least on `x86_64 Linux`. Going from that to other architectures will still take time, but it is not as far away as some might think.
Thanks for the update. I think one important issue that also needs to be resolved is adding the GCC git tree as a subproject in Rust's git tree so that in the end, it will be possible to build a Rust compiler with a rustc_codegen_gcc backend without having to resort to external repositories.
The linked article was mostly meant for people already lossely familiar with the project, but it seems it escaped its intended audience.
I do have a whole bunch of articles about the project on my website, going trough the entire journey of the project, from its start as a Rust to .NET compiler, to the current state.
I should have probably linked the previous articles in this one - I'll add that to my website. I'll also look into adding some more context to the articles next time.
I guess the complaint was more about your fans updooting stuff, so apologies if it sounded like I was shitting on this. Cool project, and I really am awaiting the presentation/writeup.
The README is slightly out of date, sorry. Supporting old platforms is one of the goals.
Truth be told, the support for C was at first added as a proff-of-concept that a Rust to C compiler is possible. But it worked surprisingly well, so I just decided to roll with it, and see where it takes me.
My policy in regards to C version is: I want to be as close to ANSI C as possible. So, I avoid modern C features as much as I can. I don't know if full compatibility is achievable, but I certainly hope so. Only time will tell.
Some simpler pieces of Rust work just fine with ANSI C compilers, but more complex code breaks(eg. due to unsupported intrinsics). If I will be able to solve that(+ some potential soundness issues) then I'll be able to use ANSI C.
I have workarounds for all "simple" cases of UB in C(this is partially what the talk is about). The test code is running with `-fsantize=undefined`, and triggers no UB checks.
There are also escape hatches for strict aliasing in the C standard - mainly using memcpy for all memory operations.
Since signed multiplication is bitwise-equivalent to unsigned multiplication, I use unsigned multiplication to emulate UB-free signed multiplication. The signed variant of this overflow check is a bit harder to read because of that, but it still works just fine.
As for using `__builtin_popcountll` instead - you are right, my mistake. Thanks for pointing that out :).
I did not use the word "unsigned" before long long for the sake of readability - I know that repeating a word so many times can make it harder to parse for some folk. The project itself uses the correct types in the code, I was just kind of loose with the language in the article itself. My bad, I'll fix that and be a bit more accurate.
Yes, the C and C++ unsigned types are analogous to Rust's Wrapping<u8> Wrapping<u16> Wrapping<u32> and so on, except that their size isn't nailed down by the ISO document.
This project did start off as a way for me to learn how Rustc works, but there are legitimate use cases (and I have been approached by people interested in using it).
The main goal of the project is allowing people to easily use existing Rust libraries from .NET. I want people to be able to use Rust libs in .NET without even knowing they were written in Rust.
Besides the main compiler part, the project also comes with a tightly integrated interop layer. While it is not finished yet, it allows you to do things like holding references to C# classes in standard Rust code. The compiler will also be able to verify your Rust/.NET interop code, ensuring it is safe and reliable.
So, someone can take, for example a Rust ML framework or a Rust physics engine, define a few .NET classes and methods (fully in Rust!) and ship a portable .NET assembly for people to use.
Since Rust manages memory explicitly, the GC will have less work to do, reducing pauses and speeding execution up. Rust code also heavily uses the stack, making it more cache-friendly.
From my benchmarks, the Rust on .NET is faster than C#, but slower than native code.
So, the overall idea is to provide an easy way to write safe .NET libraries, which are faster than existing ones, and are as convenient to use as the existing solutions.
If you have any questions regarding the project, feel free to ask :)!
The goal of my work is to allow for deeper and easier Rust/.NET interoperability.
Besides the main compiler part, the project comes bundled with an interop layer, which allows you to easily call C# code from Rust and vice versa.
Besides that, the interop layer (which is not yet finished) will also contain support for defining .NET classes from Rust code.
The main use case I imagine is using Rust libraries from .NET. This can decrease the GC usage, while still allowing you to easily hold references to managed classes.
This is also what the interop layer is geared towards: I want people to be able to quickly write managed wrappers around Rust crates, and for the Rust compiler to verify this glue code is safe, both on the Rust and .NET side. A lot of this is WIP, but in the future I will be able to fully verify the safety of such glue code.
Having a pure-il assembly also enables one executable to be used across all targets .NET supports. Adding another pure-IL dependency can be easier than adding one that ships with an unmanaged library.
The Rust to .NET translation is also very high-level: it preserves things like argument and variable names, types, field names, etc. You will also be able to catch a Rust unwind in C# code (as a normal exception) and Rust code will be able to catch .NET exceptions.
Overall, the goal is to provide more performant .NET libraries, which can be used without even knowing that they are written in Rust. This way, the cost of moving existing codebases to such libraries will be much smaller.
Please let me know if you have any other questions, I will be more than happy to answer them :).
> Besides the main compiler part, the project comes bundled with an interop layer, which allows you to easily call C# code from Rust and vice versa.
I guess the part I am still missing is when you say Rust in this context, it seems like you're essentially referring to "Rust.NET" really, and not Rust. E.g. it makes it easier to call .NET code from Rust _if_ it's using your .NET target, but Rust for other targets, not so much.
(^correct me if I'm wrong here, as the rest of the points made are based on this assumption)
This just seems contradictory to the goals of someone using .NET/Rust interop in the first place. If you're bringing in Rust, it's because you want the raw power of native code, not just the ability to easily write Rust code where you absolutely could've just written in your original .NET language (because ultimately, your compiler target is .NET, not executable code itself).
I can see many layers of abstraction dealing with this issue, but it still makes me wonder why someone wouldn't just compile Rust to a DLL and call that from .NET.
The calls from Rust -> .NET runtime could be useful, however, as I'm pretty sure you can't just load a class library dll in rust and start instantiating things from it. But at the end of the day, I can't see that being possible without loading the .NET runtime in your Rust program, which involves loading all those dependencies, which .NET languages already do very well by themselves so why not just, for example, write a Rust app and a .NET app and use IPC in such a scenario.