`unsafe` occurs in rust source code where the author of some code needs to do things in a way that can't be directly proven to the compiler to be safe. These include things like calling C functions and ASM code (both cases where we can't infer all the information necessary to ensure safety). The author of the unsafe code then provides an "safe" abstraction around the unsafety that ensures that when one uses the "safe" interface, no undefined behavior occurs.
At the lowest level there is always some unsafety: system calls, libc function invocations, asm, modifying various memory mapped registers. What rust provides vs C or C++ is effective isolation of the unsafety.
- Operating systems. For example, the voodoo that happens during early boot, where you need to walk the CPU through different modes. And also fundamental kernel stuff like mapping memory.
- Cryptography. Crypto code is often hand-written in assembly for efficiency. (Sometimes it's even the other way around: crypto algorithms may be designed with specific machine instructions in mind.) Also there are places where you have to guarantee that some operation happens in constant time, which is hard to do when a compiler may choose to insert branches or jumps without telling you.
To compete with C in those spaces, Rust will need inline assembly features.
As far as safety is concerned, yes, inline assembly is completely unsafe. In that sense, it's not so different from calling functions in the C standard library (or any other C library), which might do absolutely anything with your memory. In all of these cases, the Rust programmer has to use the `unsafe` keyword, and it's up to them to make sure that Rust's rules are still respected after the unsafe code has run. Doing this properly, and wrapping it all in a safe Rust API, means that other safe code can then use your library without the `unsafe` keyword and without any risk of triggering undefined behavior.
Isn't every system call an assembly instruction? Not just the voodoo stuff?
My only experience with "real" assembly was my OS class in college, in which a project we had involved adding system calls to Linux, and they were all snippets of assembly code called in C.
For the weirder cases like right after boot or handling an interrupt you generally just have to go full assembly for that, since in general you're not started out in a state where you can just start running your typical C/Rust/etc. code. It depends heavily on your platform at that point though.
As the post mentions, inline assembly comes in handy in a number of low level contexts (e.g. dealing with memory-mapped devices, working on microcontrollers, using processor features that aren't exposed by the kernel or standard library).
Or kernel features not exposed by the libc.
As someone who doesn't do any low-level work, could you give an example of these kinds of features? I'd like to read into some of them :)
Some C/C++ compilers will expose these instructions as intrinsics, but AFAIK Rust doesn't.
The most widespread cases of this (SSE, AVX2) came from Intel trying to get lock-in in the high-performance computing market. So it took a while for AMD to sell chips that implemented these instructions and even Intel's catalog doesn't uniformly offer them.
It's also tough to get the compiler to emit these instructions where you want even if it knows they're available (unsurprisingly, since you're asking it to auto parallelize a computation), so in the high-performance space a lot of people just have to resort to inline assembly.
What you are describing, with special instructions, is called Single Instruction Multiple Data (SIMD), or simply vector instructions.
ILP means the execution of multiple separate instructions in parallel per clock cycle, though techniques like superscalar, out-of-order and speculative execution. ILP is sometimes used as a measure: How many instructions per cycle can be issued. It does not require special instructions, it's just the hardware being clever about running existing instructions faster.
We talked about Instruction Level Parallelism vs. Thread Level Parallelism vs. Node Level Parallelism since generally if you are working on a problem with some data dependency you will really have to think about each separately to get the best performance.
Or try to program a micro-controler "hello world" that actuates an LED ?
Rust is not designed for memory safety only. If you only want that, there are other simpler options, like any functional, scripting or managed language. Instead, Rust is designed to bring as much memory safety as possible (but not more!) to the low-level and performance fields.
Rust already has unsafe blocks (explicitly marked `unsafe`) for this kind of situations. Inline assembly obviously is allowed only in unsafe contexts and should be used very carefully.