5 ms·
The title undersells it: this means that Rust can now compile to C89, by first compiling to WebAssembly and then compiling that WebAssembly to C. This addresses
by pcwalton 4y ago
The title undersells it: this means that Rust can now compile to C89, by first compiling to WebAssembly and then compiling that WebAssembly to C. This addresses one of the major concerns about Rust (and LLVM, for that matter) that I see brought up again and again here: compatibility with obscure systems that only have a C89 compiler available.
- userbinator 4y agoby first compiling to WebAssembly and then compiling that WebAssembly to C That's a really indirect way, and it's not clear how much efficiency is lost in the process. It's not too far from claiming that $language can be used on a microcontroller, because $language exists on Linux, and the latter can run Linux even if via extremely slow emulation: https://news.ycombinator.com/item?id=19762928 https://news.ycombinator.com/item?id=19762928 Also related: https://news.ycombinator.com/item?id=22010159 https://news.ycombinator.com/item?id=22010159
- hedgehog 4y agoAccording to the w2c2 readme "Coremark 1.0: ~7% slower than native" so within the generated code performance sounds quite good. What I'm curious about is how hard it is to build a library target via this method and how much overhead there is in calling the generated code. Maybe someone who knows WebAssembly has some idea? Do call parameters need to get turned into JSON and back? Can I pass in a pointer to writable memory?
- flohofwoe 4y ago'Primitive types' like integers and floats can be passed to the other side directly as function parameters without marshalling. For memory access I can only describe how it works in the browser environment with Emscripten (for lack of experience with other WASM integrations): The WASM heap is exposed as a Javascript ArrayBuffer object (or more correctly that ArrayBuffer object is the WASM heap, created on the JS side and handed to the WASM side at startup), with per-primitive-type array views (for instance for byte access there's a global "HEAPU8: Uint8Array" object on the JS side). Since WASM currently only has 32-bit pointers, pointers can be passed safely to the Javascript side as JS 'numbers' without loss of information. This 'number pointer' can then be used as array index to read and write data in the WASM heap from the JS side. Don't know how it works in WASM engines outside the browser, but I suppose it's similar (e.g. a shared heap between the native side and WASM), except maybe that you can also pass 64-bit integers around without data loss. But in no case there needs to be any JSON- or Protobuf-style 'parameter serialization' involved. This old blog post might contain some more information: https://hacks.mozilla.org/2018/10/calls-between-javascript-and-webassembly-are-finally-fast-%F0%9F%8E%89/ https://hacks.mozilla.org/2018/10/calls-between-javascript-a...
- cylon13 4y agoThere's not much data in the performance section of the front-page readme of the repo, but the one bullet point there seems promising: > Coremark 1.0: ~7% slower than native [0] [0] https://github.com/turbolent/w2c2#performance https://github.com/turbolent/w2c2#performance
- azakai 4y agoWe actually have good data on this. Very little efficiency is lost in many cases - only around 14%: https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html See also here, where wasm2c is the fastest wasm runtime: https://00f.net/2023/01/04/webassembly-benchmark-2023/ https://00f.net/2023/01/04/webassembly-benchmark-2023/ There are of course cases that can be slower, like code that depends heavily on SIMD, as wasm support for SIMD is still being improved. But in general compiling to wasm as an intermediary IR and then using an optimizing compiler can lead to very fast code.
- earthboundkid 4y agoCould you use it as a bootstrap to build the Rust compiler on the target architecture and get the 14% back?
- comex 4y agoNo need. For the Rust compiler, like most modern compilers, the list of systems it can produce binaries for is independent of which system it is running on. Either the compiler supports the instruction set and executable format used on Mac OS 9, or it doesn’t. If it does, then you could cross-compile Rust code for Mac OS 9 from any other supported system – including cross-compiling the compiler itself if desired. If it doesn’t, then it doesn’t, and even if you managed to run the compiler on Mac OS 9 (through a translation layer or otherwise), it would still only be able to produce code for its supported targets. An exception to this principle is the linker: the Rust compiler relies on an external linker, and it may happen that the standard linker for a system only runs on that system itself. This is true on modern macOS and Windows. In this case it’s impossible to cross-compile for the target normally (at least without using a nondefault linker such as LLD). But even in that case, it’s possible to separate the compile and link steps, so you could compile an object file on another system, copy the object file to the target system, and run the linker from there. That would be inconvenient but good enough for bootstrapping purposes, so a translation layer still wouldn’t really help.
- 4y ago
- pcwalton 4y agoAdding more IRs isn't necessarily a problem. Clang goes through AST -> LLVM IR -> SelectionDAG -> MachineInstr -> assembly already.
- comex 4y agoNot to be confused with obscure Linux ports that only have GCC available. This doesn’t address the problem of making (existing, cross-platform) Rust code work on those systems, since (I assume) it doesn’t provide FFI with native code. However, rustc_codegen_gcc will save the day eventually.